nexus-agents 2.128.2 → 2.128.4
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/dist/{child-mcp-config-VBBVY3UC.js → child-mcp-config-TQIZEHVP.js} +2 -2
- package/dist/{chunk-NONHL3SG.js → chunk-47M2C4SO.js} +5 -5
- package/dist/{chunk-PI4RZNLE.js → chunk-4FFWDTUE.js} +2 -2
- package/dist/{chunk-6FSMURPE.js → chunk-4IBBMLNR.js} +4 -4
- package/dist/{chunk-YEJTDLJ3.js → chunk-5QJTUA7Y.js} +3 -3
- package/dist/{chunk-BJO43VLI.js → chunk-6RXWD3HT.js} +2 -2
- package/dist/{chunk-HFIYXKDQ.js → chunk-BKZ5YD66.js} +11 -648
- package/dist/{chunk-HFIYXKDQ.js.map → chunk-BKZ5YD66.js.map} +1 -1
- package/dist/{chunk-KRBE2EVT.js → chunk-C2VEMJAJ.js} +5 -5
- package/dist/{chunk-ASASLEPQ.js → chunk-EORN73QB.js} +7 -7
- package/dist/{chunk-LIHENWIY.js → chunk-FJREQSFG.js} +2 -2
- package/dist/{chunk-5UM6PJUH.js → chunk-GO7JE2MA.js} +2 -2
- package/dist/{chunk-4FGJAUDW.js → chunk-GZFECWWZ.js} +2 -2
- package/dist/{chunk-PMTPSSYV.js → chunk-GZTPQMD5.js} +3 -3
- package/dist/{chunk-U74PCTO2.js → chunk-IASJVOVO.js} +2 -2
- package/dist/{chunk-XVWN7BIV.js → chunk-IFJQPEOV.js} +47 -35
- package/dist/{chunk-XVWN7BIV.js.map → chunk-IFJQPEOV.js.map} +1 -1
- package/dist/{chunk-LYE2ZVJT.js → chunk-IKWTX7PW.js} +7 -7
- package/dist/{chunk-UI6BFGML.js → chunk-JAKYPFLI.js} +3 -3
- package/dist/{chunk-PPNLALMH.js → chunk-JQHZS7GU.js} +4 -4
- package/dist/{chunk-IG5XPEOV.js → chunk-KYLVH42N.js} +2 -2
- package/dist/{chunk-DGLRE36W.js → chunk-NKAPCKHN.js} +4 -4
- package/dist/{chunk-MQD7Y3MY.js → chunk-QJ52FRQX.js} +2 -2
- package/dist/{chunk-2WCL6CZZ.js → chunk-RAAMLWMY.js} +7 -7
- package/dist/{chunk-3FVFOMKF.js → chunk-RFXBV3A2.js} +4 -4
- package/dist/{chunk-BCTDE4WH.js → chunk-SH6JG7GE.js} +7 -7
- package/dist/{chunk-WTLYBA3N.js → chunk-TP3VZUQL.js} +3 -3
- package/dist/{chunk-6Q57ZBDS.js → chunk-U3FNIYWH.js} +2 -2
- package/dist/{chunk-CAOOOJ2C.js → chunk-U7HHO4UI.js} +2 -2
- package/dist/{chunk-VLZLWVDU.js → chunk-V2E74WBI.js} +2 -2
- package/dist/{chunk-QT3VRHNP.js → chunk-VBAGMX5I.js} +673 -50
- package/dist/chunk-VBAGMX5I.js.map +1 -0
- package/dist/{chunk-TTWJLKRC.js → chunk-VLL4L5TK.js} +2 -2
- package/dist/{chunk-2YEF55V2.js → chunk-XMQ3EC2B.js} +2 -2
- package/dist/{chunk-6LRAILEI.js → chunk-YVJFUOHY.js} +3 -3
- package/dist/{chunk-5K77OIRA.js → chunk-ZJPKYTH5.js} +3 -3
- package/dist/{cli-circuit-breaker-DMW6E7GD.js → cli-circuit-breaker-3CWRA7DZ.js} +4 -4
- package/dist/cli.js +39 -39
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-QICBICW4.js → composite-router-MN6W5CEQ.js} +2 -2
- package/dist/{consensus-vote-QMDIDPJY.js → consensus-vote-NXBPAPFW.js} +13 -13
- package/dist/{context-retriever-3NDDAF26.js → context-retriever-OLWFVOJG.js} +8 -8
- package/dist/{doctor-deep-VDYK2ZXQ.js → doctor-deep-W3QB24SM.js} +3 -3
- package/dist/{expert-bridge-K63WNPCR.js → expert-bridge-LAB2W5ET.js} +4 -4
- package/dist/{factory-IVFZPMNV.js → factory-7ZKKQDCI.js} +5 -5
- package/dist/factory-JNLNQ67U.js +21 -0
- package/dist/{improvement-review-PFWAUIB6.js → improvement-review-ATYDIHSF.js} +4 -4
- package/dist/index.d.ts +6 -0
- package/dist/index.js +28 -28
- package/dist/{init-opencode-DUW6BYSN.js → init-opencode-4O2R5S72.js} +5 -5
- package/dist/{issue-triage-GH6S3LFF.js → issue-triage-G2AKATE4.js} +5 -5
- package/dist/{pr-reviewer-helpers-FZEO4PKE.js → pr-reviewer-helpers-Y6LEGX2P.js} +4 -4
- package/dist/{registry-command-DSZ4VUZL.js → registry-command-X6A27TNG.js} +2 -2
- package/dist/{repo-security-plan-6R5LLVWU.js → repo-security-plan-356NFHOZ.js} +3 -3
- package/dist/{research-helpers-synthesize-FYTMFLSG.js → research-helpers-synthesize-7XWIAM5D.js} +4 -4
- package/dist/{routing-memory-D2GN2JY4.js → routing-memory-YTLUUXXX.js} +2 -2
- package/dist/{session-memory-DHLQXKMF.js → session-memory-IHQCJWBK.js} +3 -3
- package/dist/{setup-command-N6OSFYCT.js → setup-command-HDI4JUYO.js} +11 -11
- package/dist/{setup-config-CSDNRV2F.js → setup-config-UA4M5OQ4.js} +3 -3
- package/dist/{setup-custom-api-TATYVC2H.js → setup-custom-api-UXFN75SS.js} +3 -3
- package/dist/{tool-memory-IQON2ASW.js → tool-memory-SJ57ZJ5F.js} +5 -5
- package/dist/{unified-registry-2PIGHEUG.js → unified-registry-WMJQUA43.js} +9 -9
- package/dist/{weather-report-ZX542NQZ.js → weather-report-WSATZR44.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-QT3VRHNP.js.map +0 -1
- package/dist/factory-36MT53K7.js +0 -21
- /package/dist/{child-mcp-config-VBBVY3UC.js.map → child-mcp-config-TQIZEHVP.js.map} +0 -0
- /package/dist/{chunk-NONHL3SG.js.map → chunk-47M2C4SO.js.map} +0 -0
- /package/dist/{chunk-PI4RZNLE.js.map → chunk-4FFWDTUE.js.map} +0 -0
- /package/dist/{chunk-6FSMURPE.js.map → chunk-4IBBMLNR.js.map} +0 -0
- /package/dist/{chunk-YEJTDLJ3.js.map → chunk-5QJTUA7Y.js.map} +0 -0
- /package/dist/{chunk-BJO43VLI.js.map → chunk-6RXWD3HT.js.map} +0 -0
- /package/dist/{chunk-KRBE2EVT.js.map → chunk-C2VEMJAJ.js.map} +0 -0
- /package/dist/{chunk-ASASLEPQ.js.map → chunk-EORN73QB.js.map} +0 -0
- /package/dist/{chunk-LIHENWIY.js.map → chunk-FJREQSFG.js.map} +0 -0
- /package/dist/{chunk-5UM6PJUH.js.map → chunk-GO7JE2MA.js.map} +0 -0
- /package/dist/{chunk-4FGJAUDW.js.map → chunk-GZFECWWZ.js.map} +0 -0
- /package/dist/{chunk-PMTPSSYV.js.map → chunk-GZTPQMD5.js.map} +0 -0
- /package/dist/{chunk-U74PCTO2.js.map → chunk-IASJVOVO.js.map} +0 -0
- /package/dist/{chunk-LYE2ZVJT.js.map → chunk-IKWTX7PW.js.map} +0 -0
- /package/dist/{chunk-UI6BFGML.js.map → chunk-JAKYPFLI.js.map} +0 -0
- /package/dist/{chunk-PPNLALMH.js.map → chunk-JQHZS7GU.js.map} +0 -0
- /package/dist/{chunk-IG5XPEOV.js.map → chunk-KYLVH42N.js.map} +0 -0
- /package/dist/{chunk-DGLRE36W.js.map → chunk-NKAPCKHN.js.map} +0 -0
- /package/dist/{chunk-MQD7Y3MY.js.map → chunk-QJ52FRQX.js.map} +0 -0
- /package/dist/{chunk-2WCL6CZZ.js.map → chunk-RAAMLWMY.js.map} +0 -0
- /package/dist/{chunk-3FVFOMKF.js.map → chunk-RFXBV3A2.js.map} +0 -0
- /package/dist/{chunk-BCTDE4WH.js.map → chunk-SH6JG7GE.js.map} +0 -0
- /package/dist/{chunk-WTLYBA3N.js.map → chunk-TP3VZUQL.js.map} +0 -0
- /package/dist/{chunk-6Q57ZBDS.js.map → chunk-U3FNIYWH.js.map} +0 -0
- /package/dist/{chunk-CAOOOJ2C.js.map → chunk-U7HHO4UI.js.map} +0 -0
- /package/dist/{chunk-VLZLWVDU.js.map → chunk-V2E74WBI.js.map} +0 -0
- /package/dist/{chunk-TTWJLKRC.js.map → chunk-VLL4L5TK.js.map} +0 -0
- /package/dist/{chunk-2YEF55V2.js.map → chunk-XMQ3EC2B.js.map} +0 -0
- /package/dist/{chunk-6LRAILEI.js.map → chunk-YVJFUOHY.js.map} +0 -0
- /package/dist/{chunk-5K77OIRA.js.map → chunk-ZJPKYTH5.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-DMW6E7GD.js.map → cli-circuit-breaker-3CWRA7DZ.js.map} +0 -0
- /package/dist/{composite-router-QICBICW4.js.map → composite-router-MN6W5CEQ.js.map} +0 -0
- /package/dist/{consensus-vote-QMDIDPJY.js.map → consensus-vote-NXBPAPFW.js.map} +0 -0
- /package/dist/{context-retriever-3NDDAF26.js.map → context-retriever-OLWFVOJG.js.map} +0 -0
- /package/dist/{doctor-deep-VDYK2ZXQ.js.map → doctor-deep-W3QB24SM.js.map} +0 -0
- /package/dist/{expert-bridge-K63WNPCR.js.map → expert-bridge-LAB2W5ET.js.map} +0 -0
- /package/dist/{factory-36MT53K7.js.map → factory-7ZKKQDCI.js.map} +0 -0
- /package/dist/{factory-IVFZPMNV.js.map → factory-JNLNQ67U.js.map} +0 -0
- /package/dist/{improvement-review-PFWAUIB6.js.map → improvement-review-ATYDIHSF.js.map} +0 -0
- /package/dist/{init-opencode-DUW6BYSN.js.map → init-opencode-4O2R5S72.js.map} +0 -0
- /package/dist/{issue-triage-GH6S3LFF.js.map → issue-triage-G2AKATE4.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-FZEO4PKE.js.map → pr-reviewer-helpers-Y6LEGX2P.js.map} +0 -0
- /package/dist/{registry-command-DSZ4VUZL.js.map → registry-command-X6A27TNG.js.map} +0 -0
- /package/dist/{repo-security-plan-6R5LLVWU.js.map → repo-security-plan-356NFHOZ.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-FYTMFLSG.js.map → research-helpers-synthesize-7XWIAM5D.js.map} +0 -0
- /package/dist/{routing-memory-D2GN2JY4.js.map → routing-memory-YTLUUXXX.js.map} +0 -0
- /package/dist/{session-memory-DHLQXKMF.js.map → session-memory-IHQCJWBK.js.map} +0 -0
- /package/dist/{setup-command-N6OSFYCT.js.map → setup-command-HDI4JUYO.js.map} +0 -0
- /package/dist/{setup-config-CSDNRV2F.js.map → setup-config-UA4M5OQ4.js.map} +0 -0
- /package/dist/{setup-custom-api-TATYVC2H.js.map → setup-custom-api-UXFN75SS.js.map} +0 -0
- /package/dist/{tool-memory-IQON2ASW.js.map → tool-memory-SJ57ZJ5F.js.map} +0 -0
- /package/dist/{unified-registry-2PIGHEUG.js.map → unified-registry-WMJQUA43.js.map} +0 -0
- /package/dist/{weather-report-ZX542NQZ.js.map → weather-report-WSATZR44.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp/middleware/validation.ts","../src/mcp/middleware/rate-limiter.ts","../src/mcp/middleware/policy-types.ts","../src/mcp/middleware/policy-helpers.ts","../src/mcp/middleware/policy-rules.ts","../src/mcp/middleware/policy.ts","../src/audit/secure-handler-audit.ts","../src/mcp/error-envelope.ts","../src/mcp/tools/tool-result.ts","../src/mcp/middleware/request-context.ts","../src/mcp/middleware/tool-input-sanitizer.ts","../src/mcp/middleware/secure-handler.ts","../src/mcp/mcp-notifier.ts","../src/mcp/middleware/tool-wrapper.ts","../src/mcp/middleware/timeout-guard.ts","../src/security/access-constraint-deriver/denylist.ts","../src/security/access-constraint-deriver/tool-risk.ts","../src/security/access-constraint-deriver/enforcer.ts","../src/security/access-constraint-deriver/mcp-guard.ts","../src/security/access-constraint-deriver/chain-adapter.ts","../src/mcp/middleware/middleware-chain.ts","../src/mcp/tools/tool-annotations.ts","../src/mcp/tool-annotations.ts","../src/consensus/types-core.ts"],"sourcesContent":["/**\n * nexus-agents/mcp - Validation Middleware\n *\n * Input validation helper using Zod schemas.\n * All tool inputs must be validated at the boundary.\n *\n * (Source: MCP Protocol 2025-11-25, Zod Documentation)\n */\n\nimport type { ZodType } from 'zod';\n\nimport { type Result, ok, err, ValidationError, formatZodError } from '../../core/index.js';\n\n// Re-export isZodError for backward compatibility\nexport { isZodError } from '../../core/index.js';\n\n/**\n * Validates tool input against a Zod schema.\n *\n * This function should be called at the start of every tool handler\n * to validate incoming arguments before processing.\n *\n * @template T - The expected type after validation\n * @param schema - The Zod schema to validate against\n * @param args - The unknown input to validate\n * @returns Result containing validated data or a ValidationError\n *\n * @example\n * ```typescript\n * const InputSchema = z.object({\n * task: z.string().min(1),\n * context: z.record(z.string(), z.unknown()).optional(),\n * });\n *\n * server.tool('my_tool', InputSchema.shape, async (args) => {\n * const result = validateToolInput(InputSchema, args);\n * if (!result.ok) {\n * return toolStructuredError({ errorCategory: 'validation', message: result.error.message });\n * }\n * const { task, context } = result.value;\n * // Process validated input...\n * });\n * ```\n */\nexport function validateToolInput<T>(\n schema: ZodType<T>,\n args: unknown\n): Result<T, ValidationError> {\n const parsed = schema.safeParse(args);\n\n if (parsed.success) {\n return ok(parsed.data);\n }\n\n const message = formatZodError(parsed.error);\n const validationError = new ValidationError(`Invalid tool input: ${message}`, {\n context: {\n issues: parsed.error.issues,\n receivedType: typeof args,\n },\n });\n\n return err(validationError);\n}\n\n/**\n * Creates a validation function bound to a specific schema.\n *\n * Useful for reusing the same schema across multiple tools.\n *\n * @template T - The expected type after validation\n * @param schema - The Zod schema to bind\n * @returns A validation function for the schema\n *\n * @example\n * ```typescript\n * const validateTask = createValidator(TaskSchema);\n *\n * // Later in tool handlers:\n * const result = validateTask(args);\n * ```\n */\nexport function createValidator<T>(\n schema: ZodType<T>\n): (args: unknown) => Result<T, ValidationError> {\n return (args: unknown) => validateToolInput(schema, args);\n}\n\n// `validateToolOutput` and `createOutputValidator` (Issue #547 sibling of\n// `validateToolInput` / `createValidator`) removed in #3022 — no MCP tool\n// ever called the output-validation path; every tool returns its result\n// without schema-validating first. If output validation comes back as a\n// real requirement, reintroduce alongside the per-tool wiring in the same\n// PR (activate-or-delete YAGNI — #2937, #2938, #2939, #2940, #3018, #3022).\n","/**\n * nexus-agents/mcp - Rate Limiter Middleware\n *\n * Token bucket implementation for rate limiting MCP tool calls.\n * Prevents abuse and ensures fair resource usage.\n *\n * (Source: Token Bucket Algorithm, RFC 6585)\n */\n\nimport { createLogger, type ILogger, getTimeProvider } from '../../core/index.js';\n\n/**\n * Configuration for the token bucket rate limiter.\n */\nexport interface RateLimiterConfig {\n /** Maximum number of tokens in the bucket */\n readonly capacity: number;\n /** Number of tokens added per interval */\n readonly refillRate: number;\n /** Interval in milliseconds between token refills (default: 1000ms) */\n readonly refillIntervalMs?: number;\n /** Optional logger instance */\n readonly logger?: ILogger;\n /** Optional identifier for logging */\n readonly name?: string;\n}\n\n/**\n * Current state of the rate limiter.\n */\nexport interface RateLimiterState {\n /** Current number of available tokens */\n readonly tokens: number;\n /** Capacity of the bucket */\n readonly capacity: number;\n /** Time until next token is available (0 if tokens available) */\n readonly nextTokenMs: number;\n}\n\n// Canonical source: config/timeouts.ts (Issue #1046)\nimport { CACHE_TIMEOUTS } from '../../config/timeouts.js';\n\nconst DEFAULT_REFILL_INTERVAL_MS = CACHE_TIMEOUTS.rateLimitRefillMs;\n\n/**\n * Token bucket rate limiter implementation.\n *\n * The token bucket algorithm allows for bursting up to the capacity,\n * while maintaining a steady-state rate equal to the refill rate.\n *\n * @example\n * ```typescript\n * const limiter = new RateLimiter({\n * capacity: 100,\n * refillRate: 10,\n * refillIntervalMs: 1000,\n * });\n *\n * if (limiter.tryAcquire()) {\n * // Proceed with operation\n * } else {\n * // Rate limited, reject or queue\n * }\n * ```\n */\nexport class RateLimiter {\n private tokens: number;\n private readonly capacity: number;\n private readonly refillRate: number;\n private readonly refillIntervalMs: number;\n private lastRefillTime: number;\n private readonly logger: ILogger;\n private readonly name: string;\n\n constructor(config: RateLimiterConfig) {\n this.capacity = config.capacity;\n this.refillRate = config.refillRate;\n this.refillIntervalMs = config.refillIntervalMs ?? DEFAULT_REFILL_INTERVAL_MS;\n this.tokens = this.capacity;\n this.lastRefillTime = getTimeProvider().now();\n this.name = config.name ?? 'rate-limiter';\n this.logger = config.logger ?? createLogger({ component: this.name });\n\n this.logger.debug('Rate limiter initialized', {\n capacity: this.capacity,\n refillRate: this.refillRate,\n refillIntervalMs: this.refillIntervalMs,\n });\n }\n\n /**\n * Refills tokens based on elapsed time.\n * Called automatically before each acquire attempt.\n */\n private refill(): void {\n const now = getTimeProvider().now();\n const elapsed = now - this.lastRefillTime;\n const intervals = Math.floor(elapsed / this.refillIntervalMs);\n\n if (intervals > 0) {\n const tokensToAdd = intervals * this.refillRate;\n this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);\n this.lastRefillTime = now - (elapsed % this.refillIntervalMs);\n\n if (tokensToAdd > 0) {\n this.logger.debug('Tokens refilled', {\n added: tokensToAdd,\n current: this.tokens,\n });\n }\n }\n }\n\n /**\n * Attempts to acquire a token.\n *\n * @param count - Number of tokens to acquire (default: 1)\n * @returns True if tokens were acquired, false if rate limited\n */\n tryAcquire(count = 1): boolean {\n this.refill();\n\n if (this.tokens >= count) {\n this.tokens -= count;\n this.logger.debug('Token acquired', {\n requested: count,\n remaining: this.tokens,\n });\n return true;\n }\n\n this.logger.warn('Rate limit exceeded', {\n requested: count,\n available: this.tokens,\n });\n return false;\n }\n\n /**\n * Gets the current state of the rate limiter.\n *\n * @returns The current rate limiter state\n */\n getState(): RateLimiterState {\n this.refill();\n\n const nextTokenMs =\n this.tokens > 0 ? 0 : this.refillIntervalMs - (getTimeProvider().now() - this.lastRefillTime);\n\n return {\n tokens: this.tokens,\n capacity: this.capacity,\n nextTokenMs: Math.max(0, nextTokenMs),\n };\n }\n\n /**\n * Resets the rate limiter to full capacity.\n * Useful for testing or after configuration changes.\n */\n reset(): void {\n this.tokens = this.capacity;\n this.lastRefillTime = getTimeProvider().now();\n this.logger.debug('Rate limiter reset', { tokens: this.tokens });\n }\n}\n\n/**\n * Creates a rate limiter with default settings suitable for MCP tools.\n *\n * Default configuration:\n * - Capacity: 100 tokens\n * - Refill rate: 10 tokens per second\n *\n * @param name - Optional name for the rate limiter\n * @param logger - Optional logger instance\n * @returns A configured RateLimiter instance\n */\nexport function createDefaultRateLimiter(name?: string, logger?: ILogger): RateLimiter {\n const config: RateLimiterConfig = {\n capacity: 100,\n refillRate: 10,\n refillIntervalMs: 1000,\n };\n if (name !== undefined) {\n (config as { name?: string }).name = name;\n }\n if (logger !== undefined) {\n (config as { logger?: ILogger }).logger = logger;\n }\n return new RateLimiter(config);\n}\n","/**\n * nexus-agents/mcp - Policy Firewall Types\n *\n * Type definitions for the authorization layer of MCP tool calls.\n *\n * (Source: OWASP ASVS 4.0, Authorization Controls)\n */\n\nimport { z } from 'zod';\n\nimport { SecurityError, type ILogger } from '../../core/index.js';\n\n// =============================================================================\n// Core Types\n// =============================================================================\n\n/**\n * Artifact type for policy context.\n * Artifacts are resources that can be referenced in policy decisions.\n */\nexport interface Artifact<T = unknown> {\n readonly id: string;\n readonly type: string;\n readonly value: T;\n readonly createdAt: Date;\n}\n\n/**\n * Execution mode for tool operations.\n * - 'read-only': Only read operations allowed (default)\n * - 'read-write': Both read and write operations allowed\n */\nexport type ExecutionMode = 'read-only' | 'read-write';\n\n/**\n * Policy enforcement mode.\n * - 'enforce': Block denied operations\n * - 'warn': Log denials but allow execution (for migration)\n */\nexport type PolicyMode = 'enforce' | 'warn';\n\n/**\n * Result of a policy evaluation.\n */\nexport interface PolicyDecision {\n readonly allowed: boolean;\n readonly reason: string;\n readonly requiredArtifact?: string;\n readonly ruleName?: string;\n}\n\n/**\n * Context provided to policy rules for evaluation.\n */\nexport interface PolicyContext {\n readonly toolName: string;\n readonly args: unknown;\n readonly mode: ExecutionMode;\n readonly artifacts?: Map<string, Artifact>;\n readonly workflowId?: string;\n readonly allowedPaths?: readonly string[];\n}\n\n/**\n * A single policy rule that can approve or deny operations.\n */\nexport interface PolicyRule {\n readonly name: string;\n readonly description: string;\n check(ctx: PolicyContext): PolicyDecision;\n}\n\n/**\n * Interface for the policy firewall.\n */\nexport interface IPolicyFirewall {\n evaluate(ctx: PolicyContext): PolicyDecision;\n addRule(rule: PolicyRule): void;\n removeRule(name: string): boolean;\n getRules(): readonly PolicyRule[];\n setMode(mode: PolicyMode): void;\n getMode(): PolicyMode;\n}\n\n/**\n * Configuration for the policy firewall.\n */\nexport interface PolicyFirewallConfig {\n /** Enforcement mode (default: 'enforce') */\n readonly mode?: PolicyMode;\n /** Logger instance */\n readonly logger?: ILogger;\n /** Initial rules to register */\n readonly rules?: readonly PolicyRule[];\n}\n\n// =============================================================================\n// Error Types\n// =============================================================================\n\n/**\n * Policy error for authorization failures.\n */\nexport class PolicyError extends SecurityError {\n readonly decision: PolicyDecision;\n\n constructor(message: string, decision: PolicyDecision) {\n super(message, {\n context: {\n allowed: decision.allowed,\n reason: decision.reason,\n ruleName: decision.ruleName,\n requiredArtifact: decision.requiredArtifact,\n },\n });\n this.name = 'PolicyError';\n this.decision = decision;\n }\n}\n\n// =============================================================================\n// Zod Schemas for Configuration\n// =============================================================================\n\n/**\n * Schema for policy configuration.\n */\nexport const PolicyConfigSchema = z.object({\n defaultMode: z.enum(['read-only', 'read-write']).default('read-only'),\n policyMode: z.enum(['enforce', 'warn']).default('enforce'),\n allowedPaths: z.array(z.string()).default(['./']),\n});\n\nexport type PolicyConfig = z.infer<typeof PolicyConfigSchema>;\n","/**\n * nexus-agents/mcp - Policy Firewall Helpers\n *\n * Utility functions for path validation and argument extraction.\n *\n * (Source: OWASP ASVS 4.0, Authorization Controls)\n */\n\n// =============================================================================\n// Path Utility Functions\n// =============================================================================\n\n/**\n * Validates a path against allowed roots.\n *\n * @param targetPath - The path to validate\n * @param allowedPaths - Array of allowed root paths\n * @returns True if the path is within an allowed root\n */\nexport function isPathSafe(targetPath: string, allowedPaths: readonly string[]): boolean {\n // Normalize the target path\n const normalizedTarget = normalizePath(targetPath);\n\n // Check if any allowed path is a prefix of the target\n for (const allowed of allowedPaths) {\n const normalizedAllowed = normalizePath(allowed);\n if (normalizedTarget.startsWith(normalizedAllowed)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Normalizes a path by removing trailing slashes and handling relative paths.\n */\nexport function normalizePath(p: string): string {\n // Remove trailing slashes\n let normalized = p.replace(/\\/{1,100}$/, '');\n\n // Handle relative paths\n if (normalized === '.') {\n normalized = '';\n } else if (normalized.startsWith('./')) {\n normalized = normalized.slice(2);\n }\n\n // Ensure absolute-like comparison\n if (!normalized.startsWith('/')) {\n normalized = '/' + normalized;\n }\n\n return normalized;\n}\n\n/**\n * Extracts path from tool arguments if present.\n */\nexport function extractPathFromArgs(args: unknown): string | undefined {\n if (args === null || typeof args !== 'object') {\n return undefined;\n }\n\n const argsObj = args as Record<string, unknown>;\n\n // Common path field names\n const pathFields = ['path', 'filePath', 'file_path', 'directory', 'dir', 'target'];\n\n for (const field of pathFields) {\n const value = argsObj[field];\n if (typeof value === 'string') {\n return value;\n }\n }\n\n return undefined;\n}\n","/**\n * nexus-agents/mcp - Policy Firewall Rules\n *\n * Default policy rules and constants for the authorization layer.\n *\n * (Source: OWASP ASVS 4.0, Authorization Controls)\n */\n\nimport type { PolicyContext, PolicyDecision, PolicyRule } from './policy-types.js';\nimport { isPathSafe, extractPathFromArgs } from './policy-helpers.js';\n\n// =============================================================================\n// Tool Classification Constants\n// =============================================================================\n\n/**\n * Tools that are considered write/mutation operations.\n */\nexport const MUTATION_TOOLS = new Set([\n 'write_file',\n 'edit_file',\n 'delete_file',\n 'create_directory',\n 'remove_directory',\n 'execute_command',\n 'run_shell',\n 'bash',\n 'create_expert',\n 'run_workflow',\n]);\n\n/**\n * Tools that are considered read-only operations.\n */\nexport const READ_ONLY_TOOLS = new Set([\n 'read_file',\n 'list_directory',\n 'search_files',\n 'get_status',\n 'orchestrate',\n 'delegate_to_model',\n]);\n\n// =============================================================================\n// Tool Classification Functions\n// =============================================================================\n\n/**\n * Checks if a tool is a mutation operation.\n */\nexport function isMutationTool(toolName: string): boolean {\n // Check explicit mutation tools\n if (MUTATION_TOOLS.has(toolName)) {\n return true;\n }\n\n // Check explicit read-only tools\n if (READ_ONLY_TOOLS.has(toolName)) {\n return false;\n }\n\n // Default to treating unknown tools as mutations (safe default)\n return true;\n}\n\n// =============================================================================\n// Default Policy Rules\n// =============================================================================\n\n/**\n * Policy rule that denies mutation operations when mode is 'read-only'.\n *\n * This ensures that write operations are only allowed when explicitly\n * enabled via the 'read-write' mode.\n */\nexport const denyMutationsWithoutModeRule: PolicyRule = {\n name: 'deny-mutations-without-mode',\n description: 'Blocks write operations unless mode is read-write',\n check(ctx: PolicyContext): PolicyDecision {\n // If mode is read-write, allow all operations\n if (ctx.mode === 'read-write') {\n return { allowed: true, reason: 'Read-write mode enabled' };\n }\n\n // Check if this is a mutation tool\n if (isMutationTool(ctx.toolName)) {\n return {\n allowed: false,\n reason: `Tool '${ctx.toolName}' is a mutation operation but mode is '${ctx.mode}'. Set mode to 'read-write' to enable.`,\n };\n }\n\n // Read-only tool in read-only mode is allowed\n return { allowed: true, reason: 'Read-only operation allowed' };\n },\n};\n\n/**\n * Policy rule that validates paths against allowed roots.\n *\n * Prevents path traversal attacks by ensuring all file operations\n * target paths within configured allowed directories.\n */\nexport const safePathsRule: PolicyRule = {\n name: 'safe-paths',\n description: 'Validates paths against allowed root directories',\n check(ctx: PolicyContext): PolicyDecision {\n // Extract path from arguments\n const targetPath = extractPathFromArgs(ctx.args);\n\n // If no path in args, allow (not a file operation)\n if (targetPath === undefined) {\n return { allowed: true, reason: 'No path argument found' };\n }\n\n // Check for obvious path traversal attempts\n if (targetPath.includes('..')) {\n return {\n allowed: false,\n reason: `Path contains '..' which may indicate path traversal: ${targetPath}`,\n };\n }\n\n // Get allowed paths from context or use default\n const allowedPaths = ctx.allowedPaths ?? ['./'];\n\n // Validate path is within allowed roots\n if (!isPathSafe(targetPath, allowedPaths)) {\n return {\n allowed: false,\n reason: `Path '${targetPath}' is outside allowed directories: ${allowedPaths.join(', ')}`,\n };\n }\n\n return { allowed: true, reason: 'Path is within allowed directories' };\n },\n};\n","/**\n * nexus-agents/mcp - Policy Firewall Middleware\n *\n * Authorization layer for MCP tool calls. Evaluates policy rules\n * to determine whether operations should be allowed or denied.\n *\n * This is separate from validation - validation checks if input is well-formed,\n * policy checks if the operation is authorized.\n *\n * (Source: OWASP ASVS 4.0, Authorization Controls)\n */\n\nimport { createLogger, type ILogger, type Result, ok, err } from '../../core/index.js';\n\nimport type {\n Artifact,\n ExecutionMode,\n PolicyMode,\n PolicyDecision,\n PolicyContext,\n PolicyRule,\n IPolicyFirewall,\n PolicyFirewallConfig,\n} from './policy-types.js';\nimport { PolicyError } from './policy-types.js';\nimport { denyMutationsWithoutModeRule, safePathsRule } from './policy-rules.js';\n\n// =============================================================================\n// PolicyFirewall Implementation\n// =============================================================================\n\n/**\n * Policy firewall that evaluates rules to authorize or deny operations.\n *\n * Rules are evaluated in order. The first rule that denies the operation\n * stops evaluation and returns the denial. If all rules pass, the operation\n * is allowed.\n *\n * @example\n * ```typescript\n * const firewall = new PolicyFirewall({ mode: 'enforce' });\n *\n * // Add rules\n * firewall.addRule(denyMutationsWithoutModeRule);\n * firewall.addRule(safePathsRule);\n *\n * // Evaluate\n * const decision = firewall.evaluate({\n * toolName: 'write_file',\n * args: { path: '/etc/passwd' },\n * mode: 'read-only',\n * });\n *\n * if (!decision.allowed) {\n * console.error(`Denied: ${decision.reason}`);\n * }\n * ```\n */\nexport class PolicyFirewall implements IPolicyFirewall {\n private readonly rules: PolicyRule[] = [];\n private mode: PolicyMode;\n private readonly logger: ILogger;\n\n constructor(config?: PolicyFirewallConfig) {\n this.mode = config?.mode ?? 'enforce';\n this.logger = config?.logger ?? createLogger({ component: 'policy-firewall' });\n\n // Register initial rules if provided\n if (config?.rules) {\n for (const rule of config.rules) {\n this.rules.push(rule);\n }\n }\n\n this.logger.debug('Policy firewall initialized', {\n mode: this.mode,\n ruleCount: this.rules.length,\n });\n }\n\n /**\n * Evaluates all policy rules against the given context.\n *\n * Rules are evaluated in order. The first rule that denies stops\n * evaluation and returns the denial decision.\n *\n * @param ctx - The policy context to evaluate\n * @returns The policy decision\n */\n evaluate(ctx: PolicyContext): PolicyDecision {\n this.logger.debug('Evaluating policy', {\n toolName: ctx.toolName,\n mode: ctx.mode,\n ruleCount: this.rules.length,\n });\n\n // If no rules, allow by default\n if (this.rules.length === 0) {\n return this.allowWithReason(ctx, 'No policy rules configured');\n }\n\n // Evaluate each rule in order\n for (const rule of this.rules) {\n const decision = rule.check(ctx);\n\n if (!decision.allowed) {\n return this.handleDenial(ctx, rule, decision);\n }\n }\n\n // All rules passed\n return this.allowWithReason(ctx, 'All policy rules passed');\n }\n\n /**\n * Creates an allow decision with the given reason and logs it.\n */\n private allowWithReason(ctx: PolicyContext, reason: string): PolicyDecision {\n const decision: PolicyDecision = { allowed: true, reason };\n this.logDecision(ctx, decision);\n return decision;\n }\n\n /**\n * Handles a rule denial, respecting warn mode if configured.\n */\n private handleDenial(\n ctx: PolicyContext,\n rule: PolicyRule,\n decision: PolicyDecision\n ): PolicyDecision {\n const denialDecision: PolicyDecision = {\n ...decision,\n ruleName: rule.name,\n };\n\n this.logDecision(ctx, denialDecision);\n\n // In warn mode, log but still allow\n if (this.mode === 'warn') {\n this.logger.warn('Policy denial overridden by warn mode', {\n toolName: ctx.toolName,\n ruleName: rule.name,\n reason: decision.reason,\n });\n return {\n allowed: true,\n reason: `[WARN MODE] Would be denied: ${decision.reason}`,\n ruleName: rule.name,\n };\n }\n\n return denialDecision;\n }\n\n /**\n * Adds a policy rule to the firewall.\n *\n * @param rule - The rule to add\n */\n addRule(rule: PolicyRule): void {\n // Prevent duplicate rules\n const existingIndex = this.rules.findIndex((r) => r.name === rule.name);\n if (existingIndex >= 0) {\n this.logger.warn('Replacing existing policy rule', { ruleName: rule.name });\n this.rules[existingIndex] = rule;\n } else {\n this.rules.push(rule);\n this.logger.debug('Policy rule added', { ruleName: rule.name });\n }\n }\n\n /**\n * Removes a policy rule by name.\n *\n * @param name - The name of the rule to remove\n * @returns True if the rule was found and removed\n */\n removeRule(name: string): boolean {\n const index = this.rules.findIndex((r) => r.name === name);\n if (index >= 0) {\n this.rules.splice(index, 1);\n this.logger.debug('Policy rule removed', { ruleName: name });\n return true;\n }\n return false;\n }\n\n /**\n * Gets all registered policy rules.\n *\n * @returns A readonly array of policy rules\n */\n getRules(): readonly PolicyRule[] {\n return [...this.rules];\n }\n\n /**\n * Sets the policy enforcement mode.\n *\n * @param mode - The new enforcement mode\n */\n setMode(mode: PolicyMode): void {\n const previousMode = this.mode;\n this.mode = mode;\n this.logger.info('Policy mode changed', { from: previousMode, to: mode });\n }\n\n /**\n * Gets the current policy enforcement mode.\n *\n * @returns The current mode\n */\n getMode(): PolicyMode {\n return this.mode;\n }\n\n /**\n * Logs a policy decision for audit purposes.\n */\n private logDecision(ctx: PolicyContext, decision: PolicyDecision): void {\n const logData = {\n toolName: ctx.toolName,\n mode: ctx.mode,\n workflowId: ctx.workflowId,\n allowed: decision.allowed,\n reason: decision.reason,\n ruleName: decision.ruleName,\n };\n\n if (decision.allowed) {\n this.logger.debug('Policy decision: ALLOWED', logData);\n } else {\n this.logger.warn('Policy decision: DENIED', logData);\n }\n }\n}\n\n// =============================================================================\n// Factory Functions\n// =============================================================================\n\n/**\n * Creates a policy firewall with default rules.\n *\n * Default rules included:\n * - deny-mutations-without-mode\n * - safe-paths\n *\n * @param config - Optional configuration\n * @returns A configured PolicyFirewall instance\n */\nexport function createDefaultPolicyFirewall(config?: PolicyFirewallConfig): PolicyFirewall {\n const firewall = new PolicyFirewall(config);\n\n // Add default rules\n firewall.addRule(denyMutationsWithoutModeRule);\n firewall.addRule(safePathsRule);\n\n return firewall;\n}\n\n/**\n * Evaluates a policy context and returns a Result.\n *\n * This is a convenience function that wraps the firewall evaluation\n * in a Result type for easier error handling.\n *\n * @param firewall - The policy firewall to use\n * @param ctx - The policy context to evaluate\n * @returns Result containing void on success or PolicyError on denial\n */\nexport function evaluatePolicy(\n firewall: IPolicyFirewall,\n ctx: PolicyContext\n): Result<void, PolicyError> {\n const decision = firewall.evaluate(ctx);\n\n if (decision.allowed) {\n return ok(undefined);\n }\n\n return err(new PolicyError(`Policy denied: ${decision.reason}`, decision));\n}\n\n/**\n * Creates a policy context from tool invocation parameters.\n *\n * @param toolName - Name of the tool being invoked\n * @param args - Tool arguments\n * @param options - Additional context options\n * @returns A PolicyContext object\n */\nexport function createPolicyContext(\n toolName: string,\n args: unknown,\n options?: {\n mode?: ExecutionMode;\n artifacts?: Map<string, Artifact>;\n workflowId?: string;\n allowedPaths?: readonly string[];\n }\n): PolicyContext {\n // Build base context with required properties\n const base = {\n toolName,\n args,\n mode: options?.mode ?? 'read-only',\n };\n\n // Use Object.assign to build result, only adding optional properties\n // when they are actually defined (to satisfy exactOptionalPropertyTypes)\n const result: Record<string, unknown> = { ...base };\n\n if (options?.artifacts !== undefined) {\n result['artifacts'] = options.artifacts;\n }\n if (options?.workflowId !== undefined) {\n result['workflowId'] = options.workflowId;\n }\n if (options?.allowedPaths !== undefined) {\n result['allowedPaths'] = options.allowedPaths;\n }\n\n return result as unknown as PolicyContext;\n}\n\n// =============================================================================\n// Re-exports for backward compatibility\n// =============================================================================\n\nexport * from './policy-types.js';\nexport * from './policy-rules.js';\nexport * from './policy-helpers.js';\n","/**\n * nexus-agents/audit - SecureHandler Audit Integration\n *\n * Integration helper to add audit logging to SecureHandler middleware.\n *\n * (Source: Issue #193 - Phase 3 structured audit logging)\n *\n * @module audit/secure-handler-audit\n */\n\nimport type { IAuditLogger, AuditActor, AuditOutcome } from './audit-types.js';\nimport type { RequestContext } from '../mcp/middleware/request-context.js';\n\n/**\n * Configuration for audit-enabled secure handler.\n */\nexport interface AuditHandlerConfig {\n /** Audit logger instance */\n auditLogger: IAuditLogger;\n /** Default actor for requests without caller info */\n defaultActor?: AuditActor | undefined;\n}\n\n/**\n * Creates an AuditActor from RequestContext.\n */\nexport function actorFromContext(ctx: RequestContext, fallback?: AuditActor): AuditActor {\n const caller = ctx.caller;\n const clientId = caller.clientId;\n if (clientId !== undefined && clientId.length > 0) {\n return {\n type: clientId.includes('api') ? 'external' : clientId.includes('cli') ? 'agent' : 'user',\n id: clientId,\n name: caller.userAgent,\n };\n }\n return fallback ?? { type: 'system', id: 'unknown', name: 'Unknown Caller' };\n}\n\n/**\n * Maps tool result to audit outcome.\n */\nexport function resultToOutcome(\n isError: boolean | undefined,\n isPolicyDenied: boolean\n): AuditOutcome {\n if (isPolicyDenied) return 'denied';\n if (isError === true) return 'failure';\n return 'success';\n}\n\n/** Options for logging tool invocation audit */\nexport interface LogToolInvocationOpts {\n auditLogger: IAuditLogger;\n toolName: string;\n outcome: AuditOutcome;\n actor: AuditActor;\n requestId: string;\n durationMs?: number | undefined;\n errorMessage?: string | undefined;\n}\n\n/**\n * Logs tool invocation to audit logger.\n */\nexport function logToolInvocationAudit(opts: LogToolInvocationOpts): void {\n opts.auditLogger.logToolInvocation({\n toolName: opts.toolName,\n outcome: opts.outcome,\n actor: opts.actor,\n requestId: opts.requestId,\n durationMs: opts.durationMs,\n errorMessage: opts.errorMessage,\n });\n}\n\n/** Options for logging policy audit */\nexport interface LogPolicyAuditOpts {\n auditLogger: IAuditLogger;\n policyName: string;\n decision: 'allow' | 'deny';\n reason: string;\n toolName: string;\n actor: AuditActor;\n requestId: string;\n}\n\n/**\n * Logs policy decision to audit logger.\n */\nexport function logPolicyAudit(opts: LogPolicyAuditOpts): void {\n opts.auditLogger.logPolicyDecision({\n policyName: opts.policyName,\n decision: opts.decision,\n reason: opts.reason,\n toolName: opts.toolName,\n actor: opts.actor,\n requestId: opts.requestId,\n });\n}\n\n/** Options for logging rate limit audit */\nexport interface LogRateLimitAuditOpts {\n auditLogger: IAuditLogger;\n toolName: string;\n actor: AuditActor;\n currentRate: number;\n limitRate: number;\n requestId: string;\n}\n\n/**\n * Logs rate limit violation to audit logger.\n */\nexport function logRateLimitAudit(opts: LogRateLimitAuditOpts): void {\n opts.auditLogger.logRateLimitViolation({\n toolName: opts.toolName,\n actor: opts.actor,\n currentRate: opts.currentRate,\n limitRate: opts.limitRate,\n requestId: opts.requestId,\n });\n}\n","/**\n * nexus-agents/mcp - Structured Tool Error Envelope\n *\n * Caller-facing error contract for MCP tools. Replaces the opaque\n * `{ isError: true, content: [{ text }] }` string shape with a structured\n * envelope so callers (other tools, voter panels, the Claude/Codex/Gemini/\n * OpenCode harnesses) can reason about retry-safety and recovery path\n * instead of string-matching arbitrary text.\n *\n * SCOPE — this envelope is caller-facing ONLY. The routing/circuit-breaker\n * layer classifies adapter subprocess failures through its own\n * `categorizeOutcomeError()` path (orchestration/outcomes/outcome-types.ts)\n * and never reads this envelope. `coarsenFailureCategory()` is a one-way\n * convenience for the rare tool that internally catches an\n * `OutcomeFailureCategory`-classified error and wants to surface it to its\n * caller — it is not, and must not become, a routing input. The two\n * taxonomies serve different layers; this is the single authoritative\n * projection between them.\n *\n * @module mcp/error-envelope\n * @see Issue #2649\n */\n\nimport { z } from 'zod';\nimport type { OutcomeFailureCategory } from '../orchestration/outcomes/outcome-types.js';\n\n// ============================================================================\n// Schema\n// ============================================================================\n\n/**\n * Caller-facing error category. Deliberately coarser than the routing\n * layer's 11-value `OutcomeFailureCategory` — a tool's caller only needs\n * enough resolution to choose a recovery path:\n *\n * - `transient` — network blip, rate limit, timeout. Retry is safe.\n * - `validation` — input shape/values wrong. Caller must fix its args.\n * - `permission` — auth / authorization / sandbox / access-policy denial.\n * - `business` — domain-logic refusal (dedup hit, precondition not met).\n * An expected, non-bug outcome — not a failure to retry.\n * - `internal` — unexpected, bug-class. Not retry-class; escalate.\n */\nexport const ErrorCategorySchema = z.enum([\n 'transient',\n 'validation',\n 'permission',\n 'business',\n 'internal',\n]);\n\nexport type ErrorCategory = z.infer<typeof ErrorCategorySchema>;\n\n/**\n * Structured error envelope returned by MCP tools. Carried in the tool\n * result's `structuredContent` under the `error` key; the human-readable\n * `message` is also mirrored into `content[].text` for display.\n */\nexport const ToolErrorEnvelopeSchema = z.object({\n errorCategory: ErrorCategorySchema,\n /** Whether retrying the same call could succeed without caller changes. */\n isRetryable: z.boolean(),\n /** Human-readable summary. Bounded to keep stack traces out of results. */\n message: z.string().min(1).max(2000),\n /**\n * Optional structured context. MUST NOT carry secrets, credentials,\n * absolute filesystem paths, or raw Error/response objects — those are\n * an information-disclosure risk (this field is not output-sanitized).\n */\n detail: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type ToolErrorEnvelope = z.infer<typeof ToolErrorEnvelopeSchema>;\n\n/**\n * `_meta` key the envelope is carried under on a tool result. It lives in\n * `_meta` — NOT `structuredContent` — because the MCP client validates\n * `structuredContent` against the tool's `outputSchema` even on error\n * results (SDK `client/index.js`: it only guards on presence, not on\n * `isError`), so an envelope in `structuredContent` breaks every tool\n * that has an `outputSchema`. `_meta` is the spec's out-of-band metadata\n * channel and is never schema-validated. Namespaced to avoid collisions.\n */\nexport const ERROR_ENVELOPE_META_KEY = 'nexus-agents/error';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Default retry-safety for a category. Only `transient` errors are\n * retry-safe by default; callers can override per-call when a specific\n * `internal` or `business` error is known to be retryable.\n */\nexport function defaultRetryable(category: ErrorCategory): boolean {\n return category === 'transient';\n}\n\n/**\n * The single authoritative projection from the routing layer's 11-value\n * `OutcomeFailureCategory` down to the 5-value caller-facing\n * `ErrorCategory`. A `Record` over every key — adding a 12th\n * `OutcomeFailureCategory` value without extending this map is a compile\n * error, which is the drift safeguard.\n *\n * One-way only: there is no `un-coarsen`, by design — the routing layer\n * keeps its own granular classification and never round-trips through here.\n */\nconst FAILURE_CATEGORY_COARSENING: Record<OutcomeFailureCategory, ErrorCategory> = {\n timeout: 'transient',\n rate_limit: 'transient',\n connection: 'transient',\n authentication: 'permission',\n validation: 'validation',\n parse: 'validation',\n crash: 'internal',\n adapter_unavailable: 'internal',\n execution: 'internal',\n generic: 'internal',\n unknown: 'internal',\n};\n\n/**\n * Coarsen a routing-layer `OutcomeFailureCategory` to a caller-facing\n * `ErrorCategory`. Use this only when a tool has caught an error already\n * classified by the routing layer and wants to surface it in its envelope.\n */\nexport function coarsenFailureCategory(category: OutcomeFailureCategory): ErrorCategory {\n return FAILURE_CATEGORY_COARSENING[category];\n}\n\n/**\n * Extract and validate a `ToolErrorEnvelope` from a tool result's `_meta`\n * object. Returns `null` when `_meta` is absent or does not carry a\n * parseable envelope under {@link ERROR_ENVELOPE_META_KEY}. Used by\n * envelope-aware callers.\n */\nexport function parseToolErrorEnvelope(meta: unknown): ToolErrorEnvelope | null {\n if (meta === null || typeof meta !== 'object') {\n return null;\n }\n const candidate = (meta as Record<string, unknown>)[ERROR_ENVELOPE_META_KEY];\n const result = ToolErrorEnvelopeSchema.safeParse(candidate);\n return result.success ? result.data : null;\n}\n","/**\n * nexus-agents/mcp - Tool Result Helpers\n *\n * Canonical type and factory functions for MCP tool results.\n * Extracted from index.ts to allow tool implementations to import\n * without circular dependencies.\n *\n * @module mcp/tools/tool-result\n */\n\nimport type { ILogger } from '../../core/index.js';\nimport type { RateLimiter } from '../middleware/rate-limiter.js';\nimport type { SecurityConfig } from '../../config/schemas.js';\nimport {\n defaultRetryable,\n ERROR_ENVELOPE_META_KEY,\n type ErrorCategory,\n type ToolErrorEnvelope,\n} from '../error-envelope.js';\n\n// ============================================================================\n// Base Dependencies\n// ============================================================================\n\n/**\n * Common dependency interface shared by all MCP tool handlers.\n *\n * Tool-specific deps interfaces should extend this base.\n * (Source: Issue #1439 — DRY extraction of 25 duplicated Deps interfaces)\n */\nexport interface BaseMcpToolDeps {\n /** Optional logger */\n logger?: ILogger;\n /** Rate limiter for throttling tool calls (required) */\n rateLimiter: RateLimiter;\n /** Security configuration (includes timeout settings) */\n security?: SecurityConfig | undefined;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * MCP tool content types.\n */\nexport interface TextContent {\n type: 'text';\n text: string;\n}\n\n/**\n * MCP tool result.\n *\n * Uses mutable properties for compatibility with secure-handler\n * sanitization (which rewrites `text` in-place).\n */\nexport interface ToolResult {\n content: Array<TextContent>;\n isError?: boolean;\n /** Structured output for SDK outputSchema validation (Issue #1117) */\n structuredContent?: Record<string, unknown>;\n /**\n * Out-of-band metadata, never validated against `outputSchema`. The\n * structured error envelope (#2649) is carried here under\n * `ERROR_ENVELOPE_META_KEY`.\n */\n _meta?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Creates a successful tool result.\n *\n * @param text - The result text\n * @returns A ToolResult with the text content\n *\n * @example\n * ```typescript\n * return toolSuccess(JSON.stringify({ status: 'ok', data: result }));\n * ```\n */\nexport function toolSuccess(text: string): ToolResult {\n return {\n content: [{ type: 'text', text }],\n };\n}\n\n/**\n * Creates a successful tool result with structured content for outputSchema validation.\n *\n * When a tool is registered with outputSchema, the SDK validates structuredContent\n * against the schema. This helper returns both text (for display) and structured data.\n *\n * @param data - The structured result data (must match the tool's outputSchema)\n * @returns A ToolResult with both text content and structuredContent\n *\n * @example\n * ```typescript\n * return toolSuccessStructured({ experts: [...], count: 10 });\n * ```\n */\nexport function toolSuccessStructured(data: Record<string, unknown>): ToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],\n structuredContent: data,\n };\n}\n\n/**\n * Input for {@link toolStructuredError}. `isRetryable` is optional — when\n * omitted it is derived from the category via `defaultRetryable()`.\n */\nexport interface ToolStructuredErrorInput {\n errorCategory: ErrorCategory;\n message: string;\n isRetryable?: boolean;\n detail?: Record<string, unknown>;\n}\n\n/**\n * Creates a structured error tool result (#2649). The envelope is carried\n * in `_meta` (under `ERROR_ENVELOPE_META_KEY`) — NOT `structuredContent`,\n * which the MCP client validates against the tool's `outputSchema` even\n * on error results. `message` is mirrored into `content[].text` for\n * display.\n *\n * @example\n * ```typescript\n * if (!validated.success) {\n * return toolStructuredError({\n * errorCategory: 'validation',\n * message: `Validation error: ${formatZodError(validated.error)}`,\n * });\n * }\n * ```\n */\nexport function toolStructuredError(input: ToolStructuredErrorInput): ToolResult {\n const envelope: ToolErrorEnvelope = {\n errorCategory: input.errorCategory,\n isRetryable: input.isRetryable ?? defaultRetryable(input.errorCategory),\n message: input.message,\n ...(input.detail !== undefined ? { detail: input.detail } : {}),\n };\n return {\n isError: true,\n content: [{ type: 'text', text: envelope.message }],\n _meta: { [ERROR_ENVELOPE_META_KEY]: envelope },\n };\n}\n\n/**\n * Creates an error tool result.\n *\n * Back-compat alias for {@link toolStructuredError} — maps to the\n * conservative `internal` / non-retryable envelope. New code should call\n * `toolStructuredError` directly with the correct category; this alias\n * exists so the ~64 legacy call sites keep working during the #2649\n * migration sweep.\n *\n * @param message - The error message\n * @returns A ToolResult with isError set to true and an `internal` envelope\n */\nexport function toolError(message: string): ToolResult {\n return toolStructuredError({ errorCategory: 'internal', message });\n}\n","/**\n * nexus-agents/mcp - Request Context Middleware\n *\n * Provides request ID generation and caller context tracking for MCP tools.\n * (Source: Issue #185 Phase 1 - Request context & PolicyFirewall integration)\n *\n * @module mcp/middleware/request-context\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { getTimeProvider } from '../../core/index.js';\nimport type { TrustTier } from '../../security/trust-types.js';\n\n/**\n * Authenticated user information.\n * (Source: Issue #739 - MCP authentication)\n */\nexport interface AuthenticatedUser {\n /** Unique user/client identifier */\n readonly id: string;\n /** Human-readable name (optional) */\n readonly name?: string;\n /** Granted permissions/scopes (optional) */\n readonly permissions?: readonly string[];\n}\n\n/**\n * Caller identification for audit trails.\n */\nexport interface CallerInfo {\n /** Client identifier (e.g., 'claude-cli', 'gemini-cli') */\n readonly clientId?: string;\n /** User agent string if available */\n readonly userAgent?: string;\n /** Session ID for request correlation */\n readonly sessionId?: string;\n /** IP address or transport identifier */\n readonly transport?: string;\n /** Whether the request is authenticated (Issue #739) */\n readonly authenticated?: boolean;\n /** Authenticated user information (Issue #739) */\n readonly authenticatedUser?: AuthenticatedUser;\n}\n\n/**\n * Request context for MCP tool invocations.\n * Immutable once created.\n */\nexport interface RequestContext {\n /** Unique request identifier (format: req_<16 hex chars>) */\n readonly requestId: string;\n /** Timestamp when request was received (ISO 8601, ET) */\n readonly timestamp: string;\n /** Tool being invoked */\n readonly toolName: string;\n /** Caller information for audit */\n readonly caller: CallerInfo;\n /**\n * Trust tier for this request (Issue #828).\n * Derived from caller authentication state:\n * - '1' = Authenticated + known client, or stdio (local-only)\n * - '2' = Authenticated via network\n * - '3' = Unauthenticated network request\n * - '4' = Request with detected injection patterns (set by sanitizer)\n */\n readonly trustTier: TrustTier;\n /** Trace ID for distributed tracing correlation */\n readonly traceId?: string;\n /** Parent span ID if part of a larger trace */\n readonly parentSpanId?: string;\n}\n\n/**\n * Options for creating a request context.\n */\nexport interface CreateContextOptions {\n /** Tool name being invoked */\n toolName: string;\n /** Optional caller information */\n caller?: CallerInfo;\n /** Optional explicit trust tier override (defaults to derived from caller) */\n trustTier?: TrustTier;\n /** Optional trace ID for correlation */\n traceId?: string;\n /** Optional parent span ID */\n parentSpanId?: string;\n}\n\n/**\n * Generates a cryptographically secure request ID.\n * Format: req_<16 hex characters>\n *\n * @returns Unique request identifier\n */\nexport function generateRequestId(): string {\n const bytes = randomBytes(8);\n return `req_${bytes.toString('hex')}`;\n}\n\n/**\n * Generates a session ID for request correlation.\n * Format: sess_<12 hex characters>\n *\n * @returns Unique session identifier\n */\nexport function generateSessionId(): string {\n const bytes = randomBytes(6);\n return `sess_${bytes.toString('hex')}`;\n}\n\n/**\n * Formats timestamp in ISO 8601 format with ET timezone.\n * (Source: CLAUDE.md - Time Authority section)\n */\nfunction formatTimestamp(): string {\n const now = new Date(getTimeProvider().now());\n const formatter = new Intl.DateTimeFormat('en-US', {\n timeZone: 'America/New_York',\n timeZoneName: 'shortOffset',\n });\n const parts = formatter.formatToParts(now);\n const offset = parts.find((p) => p.type === 'timeZoneName')?.value ?? '-05:00';\n const base = now.toLocaleString('sv-SE', {\n timeZone: 'America/New_York',\n hour12: false,\n });\n return base.replace(' ', 'T') + offset.replace('GMT', '');\n}\n\n/**\n * Derives trust tier from caller authentication state (Issue #828).\n *\n * - Authenticated + known CLI client (claude, gemini, codex) → Tier 1\n * - stdio transport (local-only, no network) → Tier 1\n * - Authenticated via network → Tier 2\n * - Unauthenticated → Tier 3\n */\nexport function deriveTrustTier(caller: CallerInfo): TrustTier {\n const knownClients = ['claude-cli', 'gemini-cli', 'codex-cli'];\n\n if (caller.transport === 'stdio') return '1';\n\n if (caller.authenticated === true) {\n if (caller.clientId !== undefined && knownClients.includes(caller.clientId)) {\n return '1';\n }\n return '2';\n }\n\n return '3';\n}\n\n/**\n * Creates an immutable request context for an MCP tool invocation.\n *\n * @param options - Context creation options\n * @returns Immutable request context\n */\nexport function createRequestContext(options: CreateContextOptions): RequestContext {\n const caller = options.caller ?? {};\n const context: RequestContext = {\n requestId: generateRequestId(),\n timestamp: formatTimestamp(),\n toolName: options.toolName,\n caller,\n trustTier: options.trustTier ?? deriveTrustTier(caller),\n ...(options.traceId !== undefined && { traceId: options.traceId }),\n ...(options.parentSpanId !== undefined && { parentSpanId: options.parentSpanId }),\n };\n\n // Freeze to ensure immutability\n return Object.freeze(context);\n}\n\n/**\n * Extracts caller info from MCP transport metadata.\n * Currently supports extracting from request headers or environment.\n *\n * @param metadata - Optional transport metadata\n * @returns Caller information\n */\nexport function extractCallerInfo(metadata?: Record<string, unknown>): CallerInfo {\n const caller: CallerInfo = {};\n\n if (metadata !== undefined) {\n // Extract all available fields from metadata\n const extracted: CallerInfo = {\n ...caller,\n ...(typeof metadata['clientId'] === 'string' ? { clientId: metadata['clientId'] } : {}),\n ...(typeof metadata['userAgent'] === 'string' ? { userAgent: metadata['userAgent'] } : {}),\n ...(typeof metadata['sessionId'] === 'string' ? { sessionId: metadata['sessionId'] } : {}),\n };\n\n // If any metadata was extracted, return it directly\n if (\n typeof metadata['clientId'] === 'string' ||\n typeof metadata['userAgent'] === 'string' ||\n typeof metadata['sessionId'] === 'string'\n ) {\n return extracted;\n }\n }\n\n // Fallback to environment variables for known CLI tools\n const claudeSession = process.env['CLAUDE_SESSION_ID'];\n if (claudeSession !== undefined) {\n return { ...caller, clientId: 'claude-cli', sessionId: claudeSession };\n }\n\n const geminiSession = process.env['GEMINI_SESSION_ID'];\n if (geminiSession !== undefined) {\n return { ...caller, clientId: 'gemini-cli', sessionId: geminiSession };\n }\n\n return caller;\n}\n\n/**\n * Formats request context for logging.\n * Extracts essential fields for log context.\n *\n * @param ctx - Request context\n * @returns Log-friendly context object\n */\nexport function contextForLogging(ctx: RequestContext): Record<string, unknown> {\n return {\n requestId: ctx.requestId,\n toolName: ctx.toolName,\n trustTier: ctx.trustTier,\n ...(ctx.caller.clientId !== undefined && { clientId: ctx.caller.clientId }),\n ...(ctx.traceId !== undefined && { traceId: ctx.traceId }),\n };\n}\n\n/**\n * Type guard to check if a value is a valid RequestContext.\n */\nexport function isRequestContext(value: unknown): value is RequestContext {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const obj = value as Record<string, unknown>;\n return (\n typeof obj['requestId'] === 'string' &&\n obj['requestId'].startsWith('req_') &&\n typeof obj['timestamp'] === 'string' &&\n typeof obj['toolName'] === 'string' &&\n typeof obj['caller'] === 'object' &&\n typeof obj['trustTier'] === 'string' &&\n ['1', '2', '3', '4'].includes(obj['trustTier'])\n );\n}\n","/**\n * nexus-agents/mcp - Tool Input Sanitizer Middleware\n *\n * Lightweight sanitization for MCP tool arguments. Strips XML-like\n * conversation injection tags and detects prompt injection patterns\n * in all string values within tool arguments.\n *\n * Defense-in-depth layer that protects against prompt injection\n * through tool arguments containing external content.\n *\n * @module mcp/middleware/tool-input-sanitizer\n * (Source: Issue #828 — Wire security modules into production pipeline)\n */\n\nimport type { ILogger } from '../../core/index.js';\n\n/**\n * Result of sanitizing tool input.\n */\nexport interface SanitizeToolInputResult {\n /** Sanitized arguments (XML tags stripped from string values) */\n readonly sanitized: unknown;\n /** Whether any modification was made */\n readonly wasModified: boolean;\n /** Count of strings that were modified */\n readonly modifiedCount: number;\n /** Injection patterns detected (for logging) */\n readonly detectedPatterns: readonly string[];\n}\n\n/**\n * XML-like tags that mimic conversation structure or system prompts.\n * Stripping these prevents prompt injection through tool arguments.\n */\nconst XML_INJECTION_PATTERN =\n /<\\/?(system|human|assistant|instructions|user|prompt|context|tool_use|tool_result)\\b[^>]*>/gi;\n\n/**\n * Patterns that indicate attempted prompt injection.\n * These are logged but not necessarily stripped (detection only).\n */\nconst INJECTION_DETECTORS: ReadonlyArray<{ name: string; pattern: RegExp }> = [\n { name: 'system_prompt_override', pattern: /ignore (?:all )?previous (?:instructions|rules)/i },\n { name: 'role_impersonation', pattern: /i(?:'m| am) the (?:repo |project )?(?:owner|admin)/i },\n { name: 'hidden_instruction', pattern: /<!--[\\s\\S]*?(?:execute|delete|merge|apply)[\\s\\S]*?-->/i },\n];\n\n/**\n * Sanitizes a single string value by stripping XML injection tags.\n * Returns the cleaned string and whether it was modified.\n */\nfunction sanitizeString(value: string): { cleaned: string; modified: boolean } {\n XML_INJECTION_PATTERN.lastIndex = 0;\n const cleaned = value.replace(XML_INJECTION_PATTERN, '');\n return { cleaned, modified: cleaned !== value };\n}\n\n/**\n * Detects injection patterns in a string without modifying it.\n */\nfunction detectPatterns(value: string): string[] {\n const detected: string[] = [];\n for (const { name, pattern } of INJECTION_DETECTORS) {\n pattern.lastIndex = 0;\n if (pattern.test(value)) {\n detected.push(name);\n }\n }\n return detected;\n}\n\n/**\n * Recursively sanitizes all string values in an object/array.\n * Returns a deep copy with XML injection tags stripped from strings.\n */\nfunction sanitizeValue(value: unknown, stats: { count: number; patterns: string[] }): unknown {\n if (typeof value === 'string') {\n const patterns = detectPatterns(value);\n if (patterns.length > 0) {\n stats.patterns.push(...patterns);\n }\n const { cleaned, modified } = sanitizeString(value);\n if (modified) stats.count++;\n return cleaned;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => sanitizeValue(item, stats));\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n result[key] = sanitizeValue(val, stats);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * Sanitizes MCP tool arguments by stripping XML injection tags\n * from all string values and detecting injection patterns.\n *\n * @param args - Tool arguments to sanitize\n * @returns Sanitized result with modification tracking\n */\nexport function sanitizeToolInput(args: unknown): SanitizeToolInputResult {\n if (args === undefined || args === null) {\n return { sanitized: args, wasModified: false, modifiedCount: 0, detectedPatterns: [] };\n }\n\n const stats = { count: 0, patterns: [] as string[] };\n const sanitized = sanitizeValue(args, stats);\n const uniquePatterns = [...new Set(stats.patterns)];\n\n return {\n sanitized,\n wasModified: stats.count > 0,\n modifiedCount: stats.count,\n detectedPatterns: uniquePatterns,\n };\n}\n\n/**\n * Logs sanitization results when modifications or detections occur.\n */\nexport function logSanitizationResult(\n result: SanitizeToolInputResult,\n logger: ILogger,\n toolName: string\n): void {\n if (result.wasModified) {\n logger.warn('Tool input sanitized — XML injection tags stripped', {\n tool: toolName,\n modifiedFields: result.modifiedCount,\n });\n }\n if (result.detectedPatterns.length > 0) {\n logger.warn('Injection patterns detected in tool input', {\n tool: toolName,\n patterns: result.detectedPatterns,\n });\n }\n}\n","/**\n * nexus-agents/mcp - Secure Handler Middleware\n *\n * Higher-order function that wraps MCP tool handlers with security middleware:\n * - RequestContext creation and tracking\n * - PolicyFirewall evaluation\n * - Logging with request context\n *\n * (Source: Issue #185 Phase 1 - PolicyFirewall integration)\n *\n * @module mcp/middleware/secure-handler\n */\n\nimport type { ILogger } from '../../core/index.js';\nimport { createLogger, getTimeProvider } from '../../core/index.js';\nimport {\n createRequestContext,\n contextForLogging,\n type RequestContext,\n type CallerInfo,\n} from './request-context.js';\nimport { type IPolicyFirewall, type ExecutionMode, createPolicyContext } from './policy.js';\nimport type { RateLimiter } from './rate-limiter.js';\nimport type { IAuditLogger } from '../../audit/audit-types.js';\nimport { actorFromContext, resultToOutcome } from '../../audit/secure-handler-audit.js';\nimport {\n sanitizeToolInput,\n logSanitizationResult,\n type SanitizeToolInputResult,\n} from './tool-input-sanitizer.js';\nimport { toolStructuredError, type ToolResult } from '../tools/tool-result.js';\n\nexport type { ToolResult };\n\n/**\n * Tool handler function signature.\n */\nexport type ToolHandler = (args: unknown) => Promise<ToolResult>;\n\n/**\n * Security tier for MCP tools. Controls input validation strictness.\n *\n * - 'standard': Default. XML injection tag stripping only (existing behavior).\n * - 'user-facing': Accepts user task descriptions. Rejects known injection patterns.\n * - 'external': Processes external URLs/content. Strictest validation.\n *\n * @see Issue #1586 — Tiered security validation\n */\nexport type SecurityTier = 'standard' | 'user-facing' | 'external';\n\n/**\n * Configuration for the secure handler wrapper.\n */\nexport interface SecureHandlerConfig {\n /** Tool name for logging and policy evaluation */\n toolName: string;\n /** Security tier controlling input validation strictness (default: 'standard') */\n securityTier?: SecurityTier;\n /** Policy firewall instance (optional - if not provided, policy checks are skipped) */\n policyFirewall?: IPolicyFirewall;\n /** Execution mode for policy evaluation */\n executionMode?: ExecutionMode;\n /** Allowed paths for file operations */\n allowedPaths?: readonly string[];\n /** Rate limiter instance (optional) */\n rateLimiter?: RateLimiter;\n /** Logger instance (optional - creates default if not provided) */\n logger?: ILogger;\n /** Caller information extractor (optional) */\n callerInfo?: CallerInfo;\n /** Audit logger for structured audit trail (Issue #740 Phase 2) */\n auditLogger?: IAuditLogger;\n}\n\n/**\n * Extended handler context passed to the wrapped handler.\n */\nexport interface HandlerContext {\n /** Request context for this invocation */\n requestContext: RequestContext;\n /** Logger with request context attached */\n logger: ILogger;\n}\n\n/**\n * Tool handler with context signature.\n */\nexport type ContextAwareHandler = (args: unknown, ctx: HandlerContext) => Promise<ToolResult>;\n\n/**\n * Creates a rate limit error response. Rate limits are transient — the\n * structured envelope marks it retryable (#2649).\n */\nfunction rateLimitError(nextTokenMs: number): ToolResult {\n return toolStructuredError({\n errorCategory: 'transient',\n message: `Rate limit exceeded. Try again in ${String(nextTokenMs)}ms.`,\n });\n}\n\n/**\n * Creates a policy denial error response — an access-control denial,\n * categorized `permission` (#2649).\n */\nfunction policyDeniedError(reason: string, requestId: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'permission',\n message: `Policy denied: ${reason} (request: ${requestId})`,\n });\n}\n\n/**\n * Creates an internal error response (#2649).\n */\nfunction internalError(message: string, requestId: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'internal',\n message: `Internal error: ${message} (request: ${requestId})`,\n });\n}\n\n/**\n * Maximum input size for tool arguments (10MB).\n * Prevents memory exhaustion from oversized payloads.\n * (Source: Issue #740 - MCP security hardening)\n */\nconst MAX_INPUT_SIZE_BYTES = 10 * 1024 * 1024;\n\n/**\n * Patterns that indicate leaked secrets in tool output.\n * Each pattern is tested against tool response text.\n */\n// #3109: every pattern is GLOBAL so `replace` redacts ALL matches, not just\n// the first — two secrets of the same shape (e.g. a rotated old+new key) must\n// both be redacted before the result reaches the MCP caller.\nconst SECRET_PATTERNS: readonly RegExp[] = [\n // API keys with common prefixes\n /\\b(sk-[a-zA-Z0-9]{20,})\\b/g,\n /\\b(pk-[a-zA-Z0-9]{20,})\\b/g,\n // AWS-style keys\n /\\b(AKIA[A-Z0-9]{16})\\b/g,\n // Bearer tokens in output\n /Bearer\\s+[a-zA-Z0-9_\\-.~+/]+=*/g,\n // Generic long hex secrets (40+ chars)\n /\\b[0-9a-f]{40,}\\b/gi,\n // password= or token= in output\n /(?:password|token|secret|apikey|api_key)\\s*[=:]\\s*\\S{8,}/gi,\n];\n\n/** Redact detected secrets from tool output text. */\nfunction sanitizeOutput(text: string, logger: ILogger): string {\n let sanitized = text;\n for (const pattern of SECRET_PATTERNS) {\n // #3109: replace unconditionally — do NOT guard with pattern.test(), which\n // advances a global regex's lastIndex and makes replace() skip earlier\n // matches. `String.replace` with a global regex redacts every occurrence\n // and resets lastIndex to 0 on completion, so the shared pattern stays\n // safe across calls. Detect a redaction via a before/after compare.\n const before = sanitized;\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n if (sanitized !== before) {\n logger.warn('Potential secret detected in tool output, redacting', {\n pattern: pattern.source.slice(0, 30),\n });\n }\n }\n return sanitized;\n}\n\n/** Sanitize all text content in a tool result (Issue #740). */\nfunction sanitizeToolResult(result: ToolResult, logger: ILogger): void {\n for (const item of result.content) {\n item.text = sanitizeOutput(item.text, logger);\n }\n}\n\n/** Validates input size and returns error if too large. */\nfunction checkInputSize(args: unknown, logger: ILogger, requestId: string): ToolResult | null {\n if (args === undefined) return null;\n const inputSize = JSON.stringify(args).length;\n if (inputSize > MAX_INPUT_SIZE_BYTES) {\n logger.warn('Input size exceeds limit', { inputSize, limit: MAX_INPUT_SIZE_BYTES });\n return internalError('Input too large', requestId);\n }\n return null;\n}\n\n/**\n * Checks rate limiter and returns error if exceeded.\n */\nfunction checkRateLimit(rateLimiter: RateLimiter, logger: ILogger): ToolResult | null {\n const acquired = rateLimiter.tryAcquire();\n if (!acquired) {\n const state = rateLimiter.getState();\n logger.warn('Rate limit exceeded');\n return rateLimitError(state.nextTokenMs);\n }\n return null;\n}\n\n/** Options for policy check */\ninterface PolicyCheckOptions {\n firewall: IPolicyFirewall;\n toolName: string;\n args: unknown;\n mode: ExecutionMode;\n allowedPaths?: readonly string[] | undefined;\n logger: ILogger;\n requestId: string;\n}\n\n/**\n * Evaluates policy firewall and returns error if denied.\n */\nfunction checkPolicy(opts: PolicyCheckOptions): ToolResult | null {\n const ctxOpts = {\n mode: opts.mode,\n ...(opts.allowedPaths && { allowedPaths: opts.allowedPaths }),\n };\n const decision = opts.firewall.evaluate(createPolicyContext(opts.toolName, opts.args, ctxOpts));\n\n if (!decision.allowed) {\n opts.logger.warn('Policy denied tool execution', {\n reason: decision.reason,\n ruleName: decision.ruleName,\n });\n return policyDeniedError(decision.reason, opts.requestId);\n }\n opts.logger.debug('Policy check passed', { reason: decision.reason });\n return null;\n}\n\n/**\n * Executes handler and logs result.\n */\nasync function executeHandler(\n handler: ToolHandler | ContextAwareHandler,\n args: unknown,\n ctx: HandlerContext,\n logger: ILogger\n): Promise<ToolResult> {\n const startTime = getTimeProvider().now();\n const result =\n handler.length >= 2 ? await handler(args, ctx) : await (handler as ToolHandler)(args);\n\n const durationMs = getTimeProvider().now() - startTime;\n if (result.isError === true) {\n logger.warn('Tool execution completed with error', { durationMs });\n } else {\n logger.info('Tool execution completed', { durationMs });\n }\n return result;\n}\n\n/** Emits an audit event for a completed tool invocation. */\nfunction emitToolAudit(\n auditLogger: IAuditLogger,\n toolName: string,\n ctx: RequestContext,\n result: ToolResult,\n durationMs: number\n): void {\n const actor = actorFromContext(ctx);\n const outcome = resultToOutcome(result.isError, false);\n auditLogger.logToolInvocation({\n toolName,\n outcome,\n actor,\n requestId: ctx.requestId,\n durationMs,\n });\n}\n\n/**\n * Emits an audit event when a tool handler throws (or returns a rejected\n * Promise) — closes the audit-trail gap where unexpected exceptions left\n * no auditor record (security-review fallout from #2191).\n */\nfunction emitToolAuditException(\n auditLogger: IAuditLogger,\n toolName: string,\n ctx: RequestContext,\n durationMs: number\n): void {\n const actor = actorFromContext(ctx);\n auditLogger.logToolInvocation({\n toolName,\n outcome: 'error',\n actor,\n requestId: ctx.requestId,\n durationMs,\n });\n}\n\n/** Emits an audit event for a policy denial. */\nfunction emitPolicyAudit(\n auditLogger: IAuditLogger,\n toolName: string,\n ctx: RequestContext,\n reason: string\n): void {\n const actor = actorFromContext(ctx);\n auditLogger.logPolicyDecision({\n policyName: 'default',\n decision: 'deny',\n reason,\n toolName,\n actor,\n requestId: ctx.requestId,\n });\n}\n\n/** Emits an audit event for a rate limit violation. */\nfunction emitRateLimitAudit(\n auditLogger: IAuditLogger,\n toolName: string,\n ctx: RequestContext\n): void {\n const actor = actorFromContext(ctx);\n auditLogger.logRateLimitViolation({\n toolName,\n actor,\n currentRate: 0,\n limitRate: 0,\n requestId: ctx.requestId,\n });\n}\n\n/** Reject inputs with detected injection patterns for elevated security tiers. */\nfunction checkSecurityTier(\n config: SecureHandlerConfig,\n sanitizeResult: SanitizeToolInputResult,\n logger: ILogger\n): ToolResult | null {\n const tier = config.securityTier ?? 'standard';\n if (tier === 'standard' || sanitizeResult.detectedPatterns.length === 0) {\n return null;\n }\n logger.warn('Input rejected by security tier validation', {\n tier,\n patterns: sanitizeResult.detectedPatterns,\n });\n // Security-tier rejection of suspected injection patterns — an\n // access-control denial, categorized `permission` (#2649).\n return toolStructuredError({\n errorCategory: 'permission',\n message:\n `Input validation failed: detected patterns [${sanitizeResult.detectedPatterns.join(', ')}]. ` +\n 'Remove prompt injection patterns and retry.',\n });\n}\n\n/** Pre-execution checks: input size, input sanitization, rate limit, policy. */\nfunction runPreChecks(\n config: SecureHandlerConfig,\n args: unknown,\n mode: ExecutionMode,\n requestContext: RequestContext,\n logger: ILogger\n): { error: ToolResult | null; sanitizedArgs: unknown } {\n const sizeResult = checkInputSize(args, logger, requestContext.requestId);\n if (sizeResult) return { error: sizeResult, sanitizedArgs: args };\n\n // Sanitize tool input: strip XML injection tags, detect injection patterns (Issue #828)\n const sanitizeResult = sanitizeToolInput(args);\n logSanitizationResult(sanitizeResult, logger, config.toolName);\n const sanitizedArgs = sanitizeResult.wasModified ? sanitizeResult.sanitized : args;\n\n // Tiered validation: reject (not strip) for user-facing/external tools (Issue #1586)\n const tierError = checkSecurityTier(config, sanitizeResult, logger);\n if (tierError !== null) return { error: tierError, sanitizedArgs };\n\n if (config.rateLimiter) {\n const rlResult = checkRateLimit(config.rateLimiter, logger);\n if (rlResult) {\n if (config.auditLogger)\n emitRateLimitAudit(config.auditLogger, config.toolName, requestContext);\n return { error: rlResult, sanitizedArgs };\n }\n }\n\n if (config.policyFirewall) {\n const pResult = checkPolicy({\n firewall: config.policyFirewall,\n toolName: config.toolName,\n args: sanitizedArgs,\n mode,\n allowedPaths: config.allowedPaths,\n logger,\n requestId: requestContext.requestId,\n });\n if (pResult) {\n if (config.auditLogger)\n emitPolicyAudit(config.auditLogger, config.toolName, requestContext, 'policy denied');\n return { error: pResult, sanitizedArgs };\n }\n }\n\n return { error: null, sanitizedArgs };\n}\n\n/**\n * Wraps a tool handler with security middleware.\n *\n * @param handler - The original tool handler or context-aware handler\n * @param config - Security configuration\n * @returns Wrapped handler with security middleware\n */\nexport function createSecureHandler(\n handler: ToolHandler | ContextAwareHandler,\n config: SecureHandlerConfig\n): ToolHandler {\n const logger = config.logger ?? createLogger({ tool: config.toolName });\n const mode = config.executionMode ?? 'read-only';\n\n return async (args: unknown): Promise<ToolResult> => {\n const ctxOpts = {\n toolName: config.toolName,\n ...(config.callerInfo && { caller: config.callerInfo }),\n };\n const requestContext = createRequestContext(ctxOpts);\n const requestLogger = logger.child(contextForLogging(requestContext));\n requestLogger.info('Tool invocation started');\n\n const { error: preCheckError, sanitizedArgs } = runPreChecks(\n config,\n args,\n mode,\n requestContext,\n requestLogger\n );\n if (preCheckError) return preCheckError;\n\n return executeAndAudit(handler, sanitizedArgs, requestContext, requestLogger, config);\n };\n}\n\n/**\n * Executes the wrapped handler with audit emission on both the success and\n * exception paths. Extracted from `createSecureHandler` to keep that\n * function within the 50-line budget.\n */\nasync function executeAndAudit(\n handler: ToolHandler | ContextAwareHandler,\n sanitizedArgs: unknown,\n requestContext: RequestContext,\n requestLogger: ILogger,\n config: SecureHandlerConfig\n): Promise<ToolResult> {\n const execStartTime = getTimeProvider().now();\n try {\n const result = await executeHandler(\n handler,\n sanitizedArgs,\n { requestContext, logger: requestLogger },\n requestLogger\n );\n sanitizeToolResult(result, requestLogger);\n if (config.auditLogger) {\n emitToolAudit(\n config.auditLogger,\n config.toolName,\n requestContext,\n result,\n getTimeProvider().now() - execStartTime\n );\n }\n return result;\n } catch (error) {\n const rawMessage = error instanceof Error ? error.message : 'Unknown error';\n requestLogger.error('Tool execution failed', error instanceof Error ? error : undefined);\n if (config.auditLogger) {\n emitToolAuditException(\n config.auditLogger,\n config.toolName,\n requestContext,\n getTimeProvider().now() - execStartTime\n );\n }\n // Closes a secret-leak path: adapter SDKs commonly echo offending\n // credentials in their error messages (e.g. Anthropic's\n // AuthenticationError carries `sk-ant-api03-…` substrings; fetch\n // wrappers can echo Authorization headers). The success branch above\n // runs sanitizeToolResult; the exception path must too.\n const sanitized = sanitizeOutput(rawMessage, requestLogger);\n return internalError(sanitized, requestContext.requestId);\n }\n}\n\n/**\n * Creates a secure handler factory with shared configuration.\n * Useful for registering multiple tools with the same security settings.\n *\n * @param sharedConfig - Shared security configuration\n * @returns Factory function for creating secure handlers\n */\nexport function createSecureHandlerFactory(\n sharedConfig: Omit<SecureHandlerConfig, 'toolName'>\n): (toolName: string, handler: ToolHandler | ContextAwareHandler) => ToolHandler {\n return (toolName: string, handler: ToolHandler | ContextAwareHandler) =>\n createSecureHandler(handler, { ...sharedConfig, toolName });\n}\n","/**\n * nexus-agents/mcp - MCP Notification Helper\n *\n * Sends structured logging notifications to MCP clients via\n * the `notifications/message` protocol method.\n * Clients (e.g., Claude Code) can display these for real-time\n * observability of orchestration events.\n *\n * Also provides progress notification support via AsyncLocalStorage\n * for resetting client-side request timeouts (MCP SDK resetTimeoutOnProgress).\n *\n * @module mcp/mcp-notifier\n * (Source: Issue #973, #974 — Claude Code Observability)\n * (Source: Issue #1108 — Progress heartbeat timeout reset)\n * (Source: MCP Protocol 2025-11-25, Logging Specification)\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { createLogger, getErrorMessage } from '../core/index.js';\n\n/**\n * Logging levels for MCP notifications (RFC 5424 syslog).\n */\nexport type McpLogLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error';\n\n/**\n * MCP notifier for sending structured log events to clients.\n */\nexport interface IMcpNotifier {\n /** Send info-level notification (key orchestration events) */\n info(logger: string, data: Record<string, unknown>): void;\n /** Send debug-level notification (detailed execution steps) */\n debug(logger: string, data: Record<string, unknown>): void;\n /** Send warning-level notification */\n warn(logger: string, data: Record<string, unknown>): void;\n}\n\nconst internalLogger = createLogger({ component: 'mcp-notifier' });\n\n/**\n * Creates an MCP notifier that sends logging notifications to connected clients.\n *\n * Notifications are fire-and-forget — failures are logged but never\n * propagate to callers. This ensures observability never breaks tool execution.\n */\nexport function createMcpNotifier(server: McpServer): IMcpNotifier {\n function send(level: McpLogLevel, logger: string, data: Record<string, unknown>): void {\n try {\n server.sendLoggingMessage({ level, logger, data }).catch((error: unknown) => {\n internalLogger.debug('Failed to send MCP notification', {\n level,\n logger,\n error: getErrorMessage(error),\n });\n });\n } catch (error: unknown) {\n internalLogger.debug('Failed to send MCP notification', {\n level,\n logger,\n error: getErrorMessage(error),\n });\n }\n }\n\n return {\n info: (logger, data) => {\n send('info', logger, data);\n },\n debug: (logger, data) => {\n send('debug', logger, data);\n },\n warn: (logger, data) => {\n send('warning', logger, data);\n },\n };\n}\n\n/**\n * No-op notifier for when MCP server is not available.\n */\nexport const NOOP_NOTIFIER: IMcpNotifier = {\n info: () => undefined,\n debug: () => undefined,\n warn: () => undefined,\n};\n\n// ============================================================================\n// Progress Notification Support (MCP SDK resetTimeoutOnProgress)\n// ============================================================================\n\n/**\n * Callback to send a progress notification to the MCP client.\n * When the client sets resetTimeoutOnProgress=true, each notification\n * resets the client's 60s request timeout.\n */\nexport type ProgressSender = (progress: number, total?: number) => void;\n\n/**\n * Progress context stored via AsyncLocalStorage.\n * Set by toSdkCallbackWithProgress when a progressToken is available.\n */\nexport interface ProgressContext {\n readonly progressToken: string | number;\n readonly sendNotification: ProgressSender;\n}\n\n/**\n * AsyncLocalStorage for MCP progress context.\n * Allows withProgressHeartbeat to access the progress sender without\n * threading it through the entire middleware chain.\n */\nexport const progressContextStorage = new AsyncLocalStorage<ProgressContext>();\n\n// ============================================================================\n// Abort Signal Support (MCP SDK cancellation)\n// ============================================================================\n\n/**\n * AsyncLocalStorage for MCP abort signal.\n * Set by toSdkCallback when the SDK provides an AbortSignal.\n * Allows middleware (e.g., TimeoutGuard) to race client cancellation\n * alongside server-side timeouts.\n */\nexport const abortSignalStorage = new AsyncLocalStorage<AbortSignal>();\n\n/**\n * Wraps an async operation with periodic heartbeat notifications.\n *\n * When a progressToken is available (via AsyncLocalStorage from the MCP\n * request handler), sends real `notifications/progress` that reset the\n * client's request timeout (MCP SDK resetTimeoutOnProgress feature).\n *\n * Always sends logging notifications for observability regardless.\n *\n * @param toolName - Name of the tool for notification context\n * @param notifier - MCP notifier instance\n * @param operation - The async operation to wrap\n * @param intervalMs - Heartbeat interval (default: 15000ms)\n * @returns The operation result\n */\nexport async function withProgressHeartbeat<T>(\n toolName: string,\n notifier: IMcpNotifier,\n operation: () => Promise<T>,\n intervalMs = 15_000\n): Promise<T> {\n const startTime = Date.now();\n let beatCount = 0;\n const progressCtx = progressContextStorage.getStore();\n\n const timer = setInterval(() => {\n beatCount++;\n const elapsed = Math.round((Date.now() - startTime) / 1000);\n\n // Send real progress notification if client provided progressToken\n if (progressCtx !== undefined) {\n progressCtx.sendNotification(beatCount);\n }\n\n // Always send logging notification for observability\n notifier.debug(toolName, {\n event: 'heartbeat',\n elapsedSeconds: elapsed,\n beatCount,\n hasProgressToken: progressCtx !== undefined,\n });\n }, intervalMs);\n\n try {\n return await operation();\n } finally {\n clearInterval(timer);\n }\n}\n","/**\n * nexus-agents/mcp - Tool Wrapper Helper\n *\n * Provides a convenient wrapper for MCP tools that automatically applies\n * the middleware chain with timeout protection (CVE-2026-0621 mitigation).\n *\n * @module mcp/middleware/tool-wrapper\n * (Source: Issue #271, CVE-2026-0621 mitigation)\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { appendFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport type { ILogger } from '../../core/index.js';\nimport type { TimeoutConfig, SecurityConfig } from '../../config/schemas.js';\nimport type { IPolicyFirewall, ExecutionMode } from './policy.js';\nimport type { RateLimiterConfig } from './rate-limiter.js';\nimport { RateLimiter } from './rate-limiter.js';\nimport {\n withMiddleware,\n createMiddlewareFactory,\n type ToolHandler,\n type ContextAwareToolHandler,\n type MiddlewareChainConfig,\n} from './middleware-chain.js';\nimport { MCP_TIMEOUTS, resolveToolClassGuardMs } from '../../config/timeouts.js';\nimport {\n progressContextStorage,\n abortSignalStorage,\n type ProgressContext,\n} from '../mcp-notifier.js';\nimport { createLogger as createInternalLogger, getErrorMessage } from '../../core/index.js';\nimport { getNexusDataDir } from '../../config/nexus-data-dir.js';\n\n/**\n * Default timeout configuration.\n * Values sourced from config/timeouts.ts (Issue #984).\n */\nexport const DEFAULT_TIMEOUT_CONFIG: TimeoutConfig = {\n defaultTimeoutMs: MCP_TIMEOUTS.defaultMs,\n maxTimeoutMs: MCP_TIMEOUTS.maxMs,\n enableLogging: true,\n uriValidation: true,\n};\n\n/**\n * Default per-tool timeout overrides.\n * Sourced from config/timeouts.ts (Issue #984).\n */\nexport const DEFAULT_TOOL_TIMEOUTS: Record<string, number> = {\n ...MCP_TIMEOUTS.perTool,\n};\n\n/**\n * Resolves the timeout for a specific tool — the central resolution chokepoint\n * (#3734). Lookup chain:\n * 1. explicit override (caller-supplied),\n * 2. security config `perToolTimeout`,\n * 3. the operation-class runaway-guard for the tool's {@link TOOL_CLASS}\n * classification (or {@link DEFAULT_OPERATION_CLASS} = 300s if unclassified),\n * honoring `NEXUS_TIMEOUT_MULTIPLIER` + per-class env overrides.\n *\n * The class-guard step replaces the old `DEFAULT_TOOL_TIMEOUTS` literal lookup\n * AND the punitive 60s global default — every tool now gets a generous\n * non-punitive runaway-guard.\n * (Issue #657 — per-tool timeout; #3734 — central class authority)\n */\nexport function getToolTimeout(\n toolName: string,\n security?: SecurityConfig,\n explicitMs?: number\n): number {\n // Explicit override takes highest priority.\n if (explicitMs !== undefined) {\n return explicitMs;\n }\n // Security config per-tool overrides still win over the class default.\n const perToolConfig = security?.timeout?.perToolTimeout;\n const perToolMs = perToolConfig?.[toolName];\n if (perToolMs !== undefined) {\n return perToolMs;\n }\n // Class-derived runaway-guard (multiplier + per-class env overrides applied).\n return resolveToolClassGuardMs(toolName);\n}\n\n/**\n * Configuration for creating a tool factory.\n */\nexport interface ToolFactoryConfig {\n /** Logger instance */\n logger?: ILogger | undefined;\n /** Security configuration (includes timeout config) */\n security?: SecurityConfig | undefined;\n /** Policy firewall instance */\n policyFirewall?: IPolicyFirewall | undefined;\n /** Rate limiter configuration */\n rateLimiter?: RateLimiterConfig | RateLimiter | undefined;\n /** Allowed paths for file operations */\n allowedPaths?: readonly string[] | undefined;\n}\n\n/**\n * Per-tool configuration options.\n */\nexport interface ToolWrapperOptions {\n /** Execution mode for policy evaluation (default: 'read-only') */\n executionMode?: ExecutionMode | undefined;\n /** Custom timeout in ms (overrides default) */\n timeoutMs?: number | undefined;\n /** Skip timeout protection (use sparingly) */\n skipTimeout?: boolean | undefined;\n /** Skip rate limiting */\n skipRateLimit?: boolean | undefined;\n}\n\n/**\n * Gets timeout configuration from security config or uses defaults.\n */\nfunction getTimeoutConfig(\n security?: SecurityConfig,\n overrideMs?: number\n): MiddlewareChainConfig['timeout'] {\n const timeoutConfig = security?.timeout ?? DEFAULT_TIMEOUT_CONFIG;\n\n return {\n defaultTimeoutMs: overrideMs ?? timeoutConfig.defaultTimeoutMs,\n maxTimeoutMs: timeoutConfig.maxTimeoutMs,\n enableLogging: timeoutConfig.enableLogging,\n };\n}\n\n/**\n * Creates a tool factory with shared configuration.\n *\n * This factory produces wrapped handlers that include timeout protection,\n * rate limiting, and other middleware as configured.\n *\n * @example\n * ```typescript\n * const wrapTool = createToolFactory({\n * security: appConfig.security,\n * rateLimiter: { capacity: 100, refillRate: 10 },\n * });\n *\n * const handler = wrapTool('my_tool', async (args) => {\n * // Your tool logic here\n * return { content: [{ type: 'text', text: 'Done' }] };\n * });\n * ```\n */\nexport function createToolFactory(\n config: ToolFactoryConfig\n): (\n toolName: string,\n handler: ContextAwareToolHandler | ToolHandler,\n options?: ToolWrapperOptions\n) => ToolHandler {\n const { security, policyFirewall, rateLimiter, allowedPaths, logger } = config;\n\n return (toolName, handler, options) => {\n const skip = {\n timeout: options?.skipTimeout,\n rateLimit: options?.skipRateLimit,\n };\n\n const chainConfig: Omit<MiddlewareChainConfig, 'toolName'> = {\n logger,\n policyFirewall,\n executionMode: options?.executionMode ?? 'read-only',\n allowedPaths,\n rateLimiter,\n timeout: skip.timeout === true ? undefined : getTimeoutConfig(security, options?.timeoutMs),\n skip,\n };\n\n return withMiddleware(toolName, handler, chainConfig);\n };\n}\n\n/**\n * Wraps a single tool handler with timeout protection.\n *\n * This is a convenience function for simple cases where you don't need\n * the full factory setup.\n *\n * @example\n * ```typescript\n * const handler = wrapToolWithTimeout('my_tool', async (args) => {\n * return { content: [{ type: 'text', text: 'Done' }] };\n * });\n * ```\n */\nexport function wrapToolWithTimeout(\n toolName: string,\n handler: ContextAwareToolHandler | ToolHandler,\n options?: {\n timeoutMs?: number;\n logger?: ILogger;\n }\n): ToolHandler {\n return withMiddleware(toolName, handler, {\n timeout: getTimeoutConfig(undefined, options?.timeoutMs),\n logger: options?.logger,\n });\n}\n\n/** Shape of the MCP SDK's extra._meta for progress tokens. */\ninterface SdkMeta {\n readonly progressToken?: string | number;\n}\n\n/** Shape of the MCP SDK's extra object passed to tool handlers. */\ninterface SdkExtra {\n readonly _meta?: SdkMeta;\n readonly signal?: AbortSignal;\n readonly sendNotification?: (notification: {\n method: string;\n params?: Record<string, unknown>;\n }) => Promise<void>;\n}\n\nconst wrapperLogger = createInternalLogger({ component: 'tool-wrapper' });\n\n/** Extract progress context from MCP SDK extra if progressToken present. */\nfunction extractProgressContext(extra: unknown): ProgressContext | undefined {\n const sdk = extra as SdkExtra | undefined;\n const token = sdk?._meta?.progressToken;\n const sendFn = sdk?.sendNotification;\n if (token === undefined || sendFn === undefined) return undefined;\n\n return {\n progressToken: token,\n sendNotification: (progress: number, total?: number) => {\n const params: Record<string, unknown> = {\n progressToken: token,\n progress,\n };\n if (total !== undefined) params['total'] = total;\n sendFn({ method: 'notifications/progress', params }).catch((err: unknown) => {\n wrapperLogger.debug('Failed to send progress notification', {\n error: getErrorMessage(err),\n });\n });\n },\n };\n}\n\n/**\n * Runs handler within nested AsyncLocalStorage contexts for progress + abort.\n */\n/** SDK-compatible tool result with optional structuredContent (Issue #1117). */\ntype SdkToolResult = {\n content: Array<{ type: 'text'; text: string }>;\n isError?: boolean;\n structuredContent?: Record<string, unknown>;\n // Post-#2649: the structured error envelope lives in `_meta` under\n // `nexus-agents/error` (not in `structuredContent`, which is validated\n // against `outputSchema` even on error results).\n _meta?: Record<string, unknown>;\n};\n\nfunction runWithContexts(\n handler: ToolHandler,\n args: unknown,\n progressCtx: ProgressContext | undefined,\n signal: AbortSignal | undefined\n): Promise<SdkToolResult> {\n const run = (): Promise<SdkToolResult> => handler(args);\n\n // Nest contexts: abort signal outer, progress inner\n if (signal !== undefined && progressCtx !== undefined) {\n return abortSignalStorage.run(signal, () => progressContextStorage.run(progressCtx, run));\n }\n if (signal !== undefined) {\n return abortSignalStorage.run(signal, run);\n }\n if (progressCtx !== undefined) {\n return progressContextStorage.run(progressCtx, run);\n }\n return run();\n}\n\n/**\n * Adapts a ToolHandler to the MCP SDK's expected callback signature.\n *\n * Extracts progressToken and AbortSignal from extra, runs the handler\n * within AsyncLocalStorage contexts so middleware can access them.\n *\n * @param handler - Our internal ToolHandler\n * @returns SDK-compatible callback function\n */\nexport function toSdkCallback(\n handler: ToolHandler\n): (args: unknown, extra: unknown) => Promise<SdkToolResult> {\n return (args: unknown, extra: unknown) => {\n const progressCtx = extractProgressContext(extra);\n const signal = (extra as SdkExtra | undefined)?.signal;\n return runWithContexts(handler, args, progressCtx, signal);\n };\n}\n\n/**\n * MCP SDK client default request timeout. Matches `DEFAULT_REQUEST_TIMEOUT_MSEC`\n * in `@modelcontextprotocol/sdk` (`shared/protocol.js`). If a tool's\n * configured server-side budget exceeds this and the client did not send a\n * `progressToken` (i.e. did not pass `onprogress` to its `request()` call),\n * the client kills the request at this threshold regardless of what the\n * server is doing — heartbeats fire but go nowhere.\n *\n * (Source: audit on #2619 / #2631 — root cause of \"MCP error -32001 at 60010ms\")\n */\nexport const MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS = 60_000;\n\n/**\n * Relative path under `$NEXUS_DATA_DIR` for the timeout-mismatch event log.\n * The #2632 WARN was log-only — useful in tail but not queryable. #2703\n * records each mismatch event as a JSONL row keyed by a correlation\n * `eventId` shared with the log entry, so \"did mismatch cause this\n * timeout?\" can be answered by joining the warning's eventId against the\n * recorded outcome — not just counted in aggregate.\n *\n * Schema lives at `docs/architecture/MCP_PROTOCOL.md` (Timeout-mismatch\n * telemetry section).\n */\nexport const TIMEOUT_MISMATCH_TELEMETRY_REL_PATH = 'mcp-telemetry/timeout-mismatch-events.jsonl';\n\n/** A single timeout-mismatch event recorded to the telemetry JSONL. */\nexport interface TimeoutMismatchEvent {\n readonly eventId: string;\n readonly toolName: string;\n readonly configuredTimeoutMs: number;\n readonly mcpSdkDefaultMs: number;\n readonly startedAt: string;\n readonly endedAt: string;\n readonly durationMs: number;\n readonly outcome: 'success' | 'error';\n /** From the post-#2649 structured error envelope when present. */\n readonly errorCategory?: string;\n readonly errorMessage?: string;\n}\n\n/**\n * Cache the \"dir ensured\" flag so we don't re-`existsSync` on every call\n * (closes #2955 site 3, partial). Cached per `dirname(path)` so an\n * operator changing `NEXUS_DATA_DIR` between calls (test/dev only)\n * still works after a process restart. The full async-write part of\n * the perf fix is deferred — `tool-wrapper-budget-check.test.ts` reads\n * the JSONL synchronously after `await callback(...)` and expects the\n * write to be visible, so switching to `fs.promises.appendFile` broke\n * those tests. The dir-cache is the cheaper part of the perf win\n * (skipping 1 existsSync per call); the appendFileSync vs appendFile\n * win can ship later behind a test-helper that awaits pending writes.\n */\nconst ensuredDirs = new Set<string>();\n\n/** Best-effort append — telemetry recording must never fail the user's tool call. */\nfunction appendTimeoutMismatchEvent(event: TimeoutMismatchEvent): void {\n try {\n const path = join(getNexusDataDir(), TIMEOUT_MISMATCH_TELEMETRY_REL_PATH);\n const dir = dirname(path);\n if (!ensuredDirs.has(dir)) {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n ensuredDirs.add(dir);\n }\n appendFileSync(path, JSON.stringify(event) + '\\n', 'utf-8');\n } catch (err) {\n wrapperLogger.debug('Best-effort timeout-mismatch event recording failed', {\n error: getErrorMessage(err),\n });\n }\n}\n\n/** Pull the post-#2649 errorCategory off an error result's `_meta` envelope. */\nfunction extractErrorCategoryFromResult(result: SdkToolResult): string | undefined {\n const envelope = result._meta?.['nexus-agents/error'];\n if (envelope !== null && typeof envelope === 'object' && 'errorCategory' in envelope) {\n const cat = (envelope as { errorCategory?: unknown }).errorCategory;\n if (typeof cat === 'string') return cat;\n }\n return undefined;\n}\n\n/** First text-content line of an error result, truncated for logging. */\nfunction extractErrorMessageFromResult(result: SdkToolResult): string | undefined {\n const first = result.content[0];\n if (first?.type === 'text' && typeof first.text === 'string') {\n return first.text.slice(0, 500);\n }\n return undefined;\n}\n\ninterface MismatchCallContext {\n readonly log: ILogger;\n readonly handler: ToolHandler;\n readonly args: unknown;\n readonly progressCtx: ProgressContext | undefined;\n readonly signal: AbortSignal | undefined;\n readonly toolName: string;\n readonly configuredTimeoutMs: number;\n}\n\ninterface MismatchOutcome {\n readonly outcome: 'success' | 'error';\n readonly errorCategory?: string;\n readonly errorMessage?: string;\n}\n\n/** Build a complete event record from a finished mismatched call. */\nfunction buildMismatchEvent(\n ctx: MismatchCallContext,\n eventId: string,\n t0: number,\n outcome: MismatchOutcome\n): TimeoutMismatchEvent {\n const t1 = Date.now();\n return {\n eventId,\n toolName: ctx.toolName,\n configuredTimeoutMs: ctx.configuredTimeoutMs,\n mcpSdkDefaultMs: MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS,\n startedAt: new Date(t0).toISOString(),\n endedAt: new Date(t1).toISOString(),\n durationMs: t1 - t0,\n outcome: outcome.outcome,\n ...(outcome.errorCategory !== undefined ? { errorCategory: outcome.errorCategory } : {}),\n ...(outcome.errorMessage !== undefined ? { errorMessage: outcome.errorMessage } : {}),\n };\n}\n\n/** Classify a tool result into a MismatchOutcome (success or structured error). */\nfunction classifyResult(result: SdkToolResult): MismatchOutcome {\n if (result.isError !== true) return { outcome: 'success' };\n const errorCategory = extractErrorCategoryFromResult(result);\n const errorMessage = extractErrorMessageFromResult(result);\n return {\n outcome: 'error',\n ...(errorCategory !== undefined ? { errorCategory } : {}),\n ...(errorMessage !== undefined ? { errorMessage } : {}),\n };\n}\n\n/** Run a mismatched call, recording its outcome to the JSONL. */\nasync function runMismatchedCall(ctx: MismatchCallContext): Promise<SdkToolResult> {\n const eventId = randomUUID();\n const t0 = Date.now();\n ctx.log.warn(\n 'MCP tool budget exceeds client default and no progressToken received — request likely to be killed by client before server-side deadline',\n {\n tool: ctx.toolName,\n eventId,\n configuredTimeoutMs: ctx.configuredTimeoutMs,\n mcpSdkDefaultMs: MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS,\n remediation:\n 'Client should pass `onprogress` and `resetTimeoutOnProgress: true` when calling, or extend `options.timeout`. See docs/architecture/MCP_PROTOCOL.md.',\n }\n );\n try {\n const result = await runWithContexts(ctx.handler, ctx.args, ctx.progressCtx, ctx.signal);\n appendTimeoutMismatchEvent(buildMismatchEvent(ctx, eventId, t0, classifyResult(result)));\n return result;\n } catch (err) {\n appendTimeoutMismatchEvent(\n buildMismatchEvent(ctx, eventId, t0, {\n outcome: 'error',\n errorMessage: getErrorMessage(err).slice(0, 500),\n })\n );\n throw err;\n }\n}\n\n/**\n * Like `toSdkCallback`, but emits a one-shot WARN at invocation start when\n * the configured per-tool budget exceeds the MCP SDK client default AND the\n * client did not send a `progressToken`. The call is almost certainly going\n * to die at the client default (~60s) regardless of server-side timeout\n * config or progress heartbeats — surface that at the moment of invocation\n * so operators can spot the mismatch in logs without waiting for the\n * timeout to fire.\n *\n * Wrap a long-running tool (`orchestrate`, `consensus_vote`,\n * `execute_expert`, `run_workflow`) with this instead of plain\n * `toSdkCallback`. Tools whose budget already fits within\n * `MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS` should keep using `toSdkCallback`.\n *\n * Each mismatch is **also recorded** to\n * `$NEXUS_DATA_DIR/mcp-telemetry/timeout-mismatch-events.jsonl` with a\n * correlation `eventId` (also surfaced in the WARN log entry) and the\n * call's eventual outcome (`success` / `error` + post-#2649 errorCategory\n * if present). This lets the Epic #2631 gate be answered with data —\n * \"of N mismatches, what fraction ended in a timeout?\" — not just counted\n * in aggregate (#2703).\n *\n * (Source: audit on #2619 / #2631 — observability for client-timeout mismatch)\n */\nexport function toSdkCallbackWithBudgetCheck(\n handler: ToolHandler,\n toolName: string,\n configuredTimeoutMs: number,\n logger?: ILogger\n): (args: unknown, extra: unknown) => Promise<SdkToolResult> {\n const log = logger ?? wrapperLogger;\n return (args: unknown, extra: unknown) => {\n const progressCtx = extractProgressContext(extra);\n const signal = (extra as SdkExtra | undefined)?.signal;\n const isMismatch =\n configuredTimeoutMs > MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS && progressCtx === undefined;\n if (!isMismatch) return runWithContexts(handler, args, progressCtx, signal);\n return runMismatchedCall({\n log,\n handler,\n args,\n progressCtx,\n signal,\n toolName,\n configuredTimeoutMs,\n });\n };\n}\n\n/**\n * Re-export middleware factory for advanced use cases.\n */\nexport { createMiddlewareFactory, withMiddleware };\n","/**\n * nexus-agents/mcp - Timeout Guard Middleware\n *\n * Provides timeout protection for MCP operations to mitigate ReDoS and\n * other denial-of-service vectors. Implements configurable timeouts with\n * proper cleanup and error handling.\n *\n * (Source: CVE-2026-0621, GHSA-8r9q-7v3j-jr4g)\n * (Source: Issue #107)\n *\n * @module mcp/middleware/timeout-guard\n */\n\nimport {\n getErrorMessage,\n createLogger,\n type ILogger,\n type Result,\n ok,\n err,\n getTimeProvider,\n} from '../../core/index.js';\n\n/**\n * Error codes for timeout-related failures.\n */\nexport type TimeoutErrorCode =\n | 'OPERATION_TIMEOUT'\n | 'OPERATION_CANCELLED'\n | 'INVALID_TIMEOUT'\n | 'GUARD_ERROR';\n\n/**\n * Timeout guard error.\n */\nexport interface TimeoutError {\n readonly code: TimeoutErrorCode;\n readonly message: string;\n readonly operation?: string;\n readonly timeoutMs?: number;\n readonly cause?: Error;\n}\n\n/**\n * Configuration for timeout guard.\n */\nexport interface TimeoutGuardConfig {\n /** Default timeout in milliseconds (default: 30000) */\n readonly defaultTimeoutMs?: number;\n /** Maximum allowed timeout in milliseconds (default: 300000) */\n readonly maxTimeoutMs?: number;\n /** Whether to log timeout events (default: true) */\n readonly enableLogging?: boolean;\n /** Logger instance */\n readonly logger?: ILogger;\n}\n\n/**\n * Result of a guarded operation.\n */\nexport interface GuardedResult<T> {\n /** The operation result */\n readonly value: T;\n /** Execution duration in milliseconds */\n readonly durationMs: number;\n /** Whether the operation was near timeout */\n readonly nearTimeout: boolean;\n}\n\n/** Execution options for guarded operations. */\nexport interface ExecuteOptions {\n /** Custom timeout for this operation */\n readonly timeoutMs?: number;\n /** Name for logging/debugging */\n readonly operationName?: string;\n /** Cleanup function to call on timeout */\n readonly onTimeout?: () => void;\n /** AbortSignal for client-initiated cancellation */\n readonly signal?: AbortSignal;\n}\n\n// Canonical source: config/timeouts.ts (Issue #1046)\nimport { TIMEOUT_GUARD } from '../../config/timeouts.js';\n\nconst DEFAULT_TIMEOUT_MS = TIMEOUT_GUARD.defaultMs;\nconst MAX_TIMEOUT_MS = TIMEOUT_GUARD.maxMs;\nconst NEAR_TIMEOUT_THRESHOLD = TIMEOUT_GUARD.nearTimeoutThreshold;\n\n/** Internal state for tracking timeout. */\ninterface TimeoutState {\n timeoutId: ReturnType<typeof setTimeout> | undefined;\n timedOut: boolean;\n}\n\n/**\n * Creates a timeout error for operation timeout.\n */\nfunction createTimeoutError(operationName: string, timeoutMs: number): TimeoutError {\n return {\n code: 'OPERATION_TIMEOUT',\n message: `Operation '${operationName}' timed out after ${String(timeoutMs)}ms`,\n operation: operationName,\n timeoutMs,\n };\n}\n\n/**\n * Creates a guard error from a caught exception.\n */\nfunction createGuardError(error: unknown, operationName: string): TimeoutError {\n const guardError: TimeoutError = {\n code: 'GUARD_ERROR',\n message: getErrorMessage(error),\n operation: operationName,\n };\n if (error instanceof Error) {\n return { ...guardError, cause: error };\n }\n return guardError;\n}\n\n/**\n * Timeout guard for protecting async operations from hanging.\n *\n * Provides protection against:\n * - ReDoS attacks (CVE-2026-0621)\n * - Slow/hanging external services\n * - Resource exhaustion\n *\n * @example\n * ```typescript\n * const guard = new TimeoutGuard({ defaultTimeoutMs: 5000 });\n *\n * const result = await guard.execute(\n * () => someAsyncOperation(),\n * { operationName: 'process-uri' }\n * );\n *\n * if (result.ok) {\n * console.log('Completed in', result.value.durationMs, 'ms');\n * }\n * ```\n */\nexport class TimeoutGuard {\n private readonly defaultTimeoutMs: number;\n private readonly maxTimeoutMs: number;\n private readonly enableLogging: boolean;\n private readonly logger: ILogger;\n\n constructor(config?: TimeoutGuardConfig) {\n this.defaultTimeoutMs = config?.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxTimeoutMs = config?.maxTimeoutMs ?? MAX_TIMEOUT_MS;\n this.enableLogging = config?.enableLogging ?? true;\n this.logger = config?.logger ?? createLogger({ component: 'timeout-guard' });\n }\n\n /** Resolves effective timeout and operation name from options. */\n private resolveOptions(options?: ExecuteOptions): {\n timeoutMs: number;\n operationName: string;\n } {\n return {\n timeoutMs: Math.min(options?.timeoutMs ?? this.defaultTimeoutMs, this.maxTimeoutMs),\n operationName: options?.operationName ?? 'unknown',\n };\n }\n\n /**\n * Executes an async operation with timeout protection.\n */\n async execute<T>(\n operation: () => Promise<T>,\n options?: ExecuteOptions\n ): Promise<Result<GuardedResult<T>, TimeoutError>> {\n const { timeoutMs, operationName } = this.resolveOptions(options);\n\n const validationError = this.validateTimeout(timeoutMs, operationName);\n if (validationError !== null) {\n return err(validationError);\n }\n\n return this.runGuarded(operation, timeoutMs, operationName, options);\n }\n\n /** Runs the operation with timeout and optional abort signal. */\n private async runGuarded<T>(\n operation: () => Promise<T>,\n timeoutMs: number,\n operationName: string,\n options?: ExecuteOptions\n ): Promise<Result<GuardedResult<T>, TimeoutError>> {\n this.logStart(operationName, timeoutMs);\n const startTime = getTimeProvider().now();\n const state: TimeoutState = { timeoutId: undefined, timedOut: false };\n\n try {\n const result = await this.runWithTimeout(\n operation,\n timeoutMs,\n state,\n options?.onTimeout,\n options?.signal\n );\n return this.handleSuccess(result, startTime, timeoutMs, operationName);\n } catch {\n const cancelled = options?.signal?.aborted === true && !state.timedOut;\n return err(\n this.handleFailure(state.timedOut, operationName, timeoutMs, startTime, cancelled)\n );\n } finally {\n if (state.timeoutId !== undefined) {\n clearTimeout(state.timeoutId);\n }\n }\n }\n\n private validateTimeout(timeoutMs: number, operationName: string): TimeoutError | null {\n if (timeoutMs <= 0) {\n return {\n code: 'INVALID_TIMEOUT',\n message: `Invalid timeout: ${String(timeoutMs)}ms`,\n operation: operationName,\n };\n }\n return null;\n }\n\n private logStart(operationName: string, timeoutMs: number): void {\n if (this.enableLogging) {\n this.logger.debug('Starting guarded operation', { operation: operationName, timeoutMs });\n }\n }\n\n private async runWithTimeout<T>(\n operation: () => Promise<T>,\n timeoutMs: number,\n state: TimeoutState,\n onTimeout?: () => void,\n signal?: AbortSignal\n ): Promise<T> {\n const timeoutPromise = new Promise<never>((_resolve, reject) => {\n state.timeoutId = setTimeout(() => {\n state.timedOut = true;\n onTimeout?.();\n reject(new Error(`Operation timed out after ${String(timeoutMs)}ms`));\n }, timeoutMs);\n });\n\n const promises: Array<Promise<T>> = [operation(), timeoutPromise];\n\n // Race against client AbortSignal if provided\n if (signal !== undefined && !signal.aborted) {\n const abortPromise = new Promise<never>((_resolve, reject) => {\n signal.addEventListener(\n 'abort',\n () => {\n reject(new Error('Operation cancelled by client'));\n },\n { once: true }\n );\n });\n promises.push(abortPromise);\n }\n\n return Promise.race(promises);\n }\n\n private handleSuccess<T>(\n result: T,\n startTime: number,\n timeoutMs: number,\n operationName: string\n ): Result<GuardedResult<T>, TimeoutError> {\n const durationMs = getTimeProvider().now() - startTime;\n const nearTimeout = durationMs > timeoutMs * NEAR_TIMEOUT_THRESHOLD;\n\n if (nearTimeout && this.enableLogging) {\n this.logger.warn('Operation completed near timeout threshold', {\n operation: operationName,\n durationMs,\n timeoutMs,\n thresholdPercent: Math.round((durationMs / timeoutMs) * 100),\n });\n }\n\n if (this.enableLogging) {\n this.logger.debug('Guarded operation completed', { operation: operationName, durationMs });\n }\n\n return ok({ value: result, durationMs, nearTimeout });\n }\n\n private handleFailure(\n timedOut: boolean,\n operationName: string,\n timeoutMs: number,\n startTime: number,\n cancelled = false\n ): TimeoutError {\n const durationMs = getTimeProvider().now() - startTime;\n\n if (cancelled) {\n this.logger.info('Operation cancelled by client', {\n operation: operationName,\n durationMs,\n });\n return {\n code: 'OPERATION_CANCELLED',\n message: `Operation '${operationName}' cancelled by client`,\n operation: operationName,\n };\n }\n\n if (timedOut) {\n this.logger.error('Operation timed out', undefined, {\n operation: operationName,\n timeoutMs,\n durationMs,\n });\n return createTimeoutError(operationName, timeoutMs);\n }\n\n return createGuardError(new Error('Unknown error'), operationName);\n }\n\n /**\n * Creates a guarded version of an async function.\n */\n guard<TArgs extends unknown[], TResult>(\n fn: (...args: TArgs) => Promise<TResult>,\n options?: { readonly timeoutMs?: number; readonly operationName?: string }\n ): (...args: TArgs) => Promise<Result<GuardedResult<TResult>, TimeoutError>> {\n return async (...args: TArgs): Promise<Result<GuardedResult<TResult>, TimeoutError>> => {\n return this.execute(() => fn(...args), options);\n };\n }\n}\n\n/**\n * URI validation utilities to complement timeout protection.\n */\nexport const UriValidation = {\n MAX_URI_LENGTH: 8192,\n MAX_TEMPLATE_DEPTH: 3,\n SUSPICIOUS_PATTERN: /\\{[+#./;?&]?[^}]*\\*\\}.*\\{[+#./;?&]?[^}]*\\*\\}|\\{(?:[^{}]*\\{){3,}/,\n\n validate(uri: string): Result<string, TimeoutError> {\n if (uri.length > this.MAX_URI_LENGTH) {\n return err({\n code: 'GUARD_ERROR',\n message: `URI exceeds maximum length: ${String(uri.length)} > ${String(this.MAX_URI_LENGTH)}`,\n operation: 'uri-validation',\n });\n }\n\n if (this.SUSPICIOUS_PATTERN.test(uri)) {\n return err({\n code: 'GUARD_ERROR',\n message: 'URI contains suspicious patterns that may cause performance issues',\n operation: 'uri-validation',\n });\n }\n\n return ok(uri);\n },\n\n sanitize(uri: string): string {\n const sanitized = uri.slice(0, this.MAX_URI_LENGTH);\n let depth = 0;\n let result = '';\n\n for (const char of sanitized) {\n if (char === '{') {\n depth++;\n if (depth > this.MAX_TEMPLATE_DEPTH) continue;\n } else if (char === '}') {\n if (depth > this.MAX_TEMPLATE_DEPTH) {\n depth--;\n continue;\n }\n depth--;\n }\n result += char;\n }\n\n return result;\n },\n};\n\n/**\n * Creates a timeout guard with default MCP-appropriate settings.\n */\nexport function createDefaultTimeoutGuard(logger?: ILogger): TimeoutGuard {\n const config: TimeoutGuardConfig = {\n defaultTimeoutMs: DEFAULT_TIMEOUT_MS,\n maxTimeoutMs: MAX_TIMEOUT_MS,\n enableLogging: true,\n };\n if (logger !== undefined) {\n return new TimeoutGuard({ ...config, logger });\n }\n return new TimeoutGuard(config);\n}\n","/**\n * Access Constraint Deriver — Unbypassable denylist (#1977 condition 3).\n *\n * Hardcoded patterns that no LLM-derived policy may override. Applied FIRST\n * in the enforcer, before checking the per-task policy. If the LLM (or a\n * malicious user objective) produces a policy that would allow access to\n * `.env`, SSH keys, cloud credentials, or similar, the denylist still wins.\n *\n * This exists because the LLM deriver is the weakest link — a user objective\n * that says \"I need to view my AWS credentials to debug\" would otherwise\n * produce a policy allowing `~/.aws/**`. The denylist refuses regardless.\n *\n * @module security/access-constraint-deriver/denylist\n */\n\n/**\n * File-path patterns that are unconditionally denied. Glob-style wildcards.\n * All matching is case-insensitive to catch `~/.SSH` and similar.\n */\nexport const UNBYPASSABLE_PATH_PATTERNS: readonly string[] = [\n // Environment files\n '.env',\n '.env.*',\n '**/.env',\n '**/.env.*',\n\n // SSH credentials\n '~/.ssh/**',\n '**/ssh/id_*',\n '**/*_rsa',\n '**/*_ed25519',\n '**/*.pem',\n\n // Cloud credentials\n '~/.aws/**',\n '~/.azure/**',\n '~/.gcp/**',\n '~/.config/gcloud/**',\n '~/.kube/config',\n\n // Unix secret files\n '/etc/shadow',\n '/etc/sudoers',\n '/etc/sudoers.d/**',\n\n // Common secret file patterns\n '**/secrets.*',\n '**/credentials.*',\n '**/private_key.*',\n '**/id_rsa*',\n];\n\n/**\n * Tool names that are unconditionally denied regardless of derived policy.\n * These are tools that should never be callable during automated agent\n * dispatch — they require explicit human action.\n */\nexport const UNBYPASSABLE_TOOL_NAMES: readonly string[] = [\n // Destructive git operations\n 'git_push_force',\n 'git_reset_hard',\n 'git_branch_delete_force',\n 'git_clean_force',\n\n // Destructive filesystem\n 'rm_recursive_force',\n 'chmod_recursive',\n\n // Identity / auth mutations\n 'ssh_add_key',\n 'gpg_add_key',\n 'npm_publish_force',\n\n // Remote destruction\n 'github_repo_delete',\n 'github_org_transfer',\n 'aws_account_close',\n];\n\n/**\n * Compiles a glob pattern to a regex at module-load time.\n * Supports: `**` (any path segments), `*` (any non-separator chars),\n * `~/` (home-anchor prefix). All other regex metachars escaped.\n *\n * Regexes built here come from the hardcoded `UNBYPASSABLE_PATH_PATTERNS`\n * constant — never from user input — so they are ReDoS-safe by construction.\n */\nfunction compileGlobToRegex(pattern: string): RegExp {\n const pat = pattern.toLowerCase();\n // Escape regex metacharacters INCLUDING backslash (per CodeQL — without\n // backslash in the class, a `\\` in input would leak into the regex output\n // unescaped). Do NOT escape `*` here — it's a glob wildcard that the\n // subsequent replaces expand into regex wildcards.\n const escaped = pat\n .replace(/[\\\\.+^$()|[\\]{}]/g, '\\\\$&')\n .replace(/\\*\\*/g, '__DOUBLESTAR__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DOUBLESTAR__/g, '.*');\n const anchored = escaped.startsWith('~/')\n ? `(^|/)${escaped.slice(2)}$`\n : escaped.startsWith('/')\n ? `^${escaped}$`\n : `(^|/)${escaped}$`;\n return new RegExp(anchored);\n}\n\n/**\n * Precompiled regexes for every unbypassable path pattern, computed once\n * at module load. Static inputs → no ReDoS surface.\n */\nconst COMPILED_PATH_PATTERNS: ReadonlyArray<{\n readonly pattern: string;\n readonly regex: RegExp;\n}> = UNBYPASSABLE_PATH_PATTERNS.map((pattern) => ({\n pattern,\n regex: compileGlobToRegex(pattern),\n}));\n\n/**\n * Returns true if a lowercased file path matches the given pattern.\n * Exported for tests; production code should use `isPathDenied`.\n */\nexport function matchDenyPattern(path: string, pattern: string): boolean {\n const normalized = path.toLowerCase();\n const compiled = COMPILED_PATH_PATTERNS.find((c) => c.pattern === pattern);\n if (compiled !== undefined) return compiled.regex.test(normalized);\n // Fallback for ad-hoc test patterns not in the static list.\n return compileGlobToRegex(pattern).test(normalized);\n}\n\n/** Returns true if the path hits any unbypassable pattern. */\nexport function isPathDenied(path: string): boolean {\n const normalized = path.toLowerCase();\n return COMPILED_PATH_PATTERNS.some((c) => c.regex.test(normalized));\n}\n\n/** Returns true if the tool name is unconditionally denied. */\nexport function isToolDenied(toolName: string): boolean {\n return UNBYPASSABLE_TOOL_NAMES.includes(toolName);\n}\n","/**\n * Tool risk classification for `confirm_risky` access-policy mode (#2279).\n *\n * Classifies each registered MCP tool as `read-only` (safe — log-and-allow\n * under confirm_risky) or `risky` (write/exec/network — block under\n * confirm_risky). Used by the policy enforcer to differentiate which\n * violations a human would have wanted to review.\n *\n * Classification policy:\n *\n * - **Read-only**: tool exclusively reads existing state — no file writes,\n * no subprocess execution, no network requests beyond a single bounded\n * read of project-internal data. `query_*`, `list_*`, `search_*`,\n * `*_query`, `*_analyze` patterns by default.\n * - **Risky**: tool writes files, runs subprocesses, posts to external\n * services, calls LLM APIs, or has any side effect that a human reviewer\n * would want to see before approving in confirm_risky mode.\n *\n * If a tool is unknown, it is treated as risky (default-deny) — same\n * principle as the unbypassable denylist: the security layer fails closed\n * on a misclassification.\n *\n * Update path: when adding a new MCP tool, classify it explicitly here.\n * The `inject-governance.ts check` CI gate ensures the registry list is\n * still the source of truth; this file is the risk overlay.\n *\n * @module security/access-constraint-deriver/tool-risk\n */\n\n/**\n * Tools that exclusively read state. Violations on these are log-and-allow\n * under `confirm_risky` mode — same as `audit` mode.\n */\nexport const READ_ONLY_TOOLS: ReadonlySet<string> = new Set([\n // Discovery / listing\n 'list_experts',\n 'list_workflows',\n // Research reads\n 'research_query',\n 'research_analyze',\n 'research_catalog_review',\n 'research_synthesize',\n // Memory reads\n 'memory_query',\n 'memory_stats',\n // Observability\n 'weather_report',\n 'query_trace',\n 'query_task_state',\n // Async-mode result polling (#3042 / epic #2631)\n 'get_job_result',\n // Async-mode job discovery (#3046 / epic #2631 Stage 5)\n 'list_jobs',\n // Codebase intelligence (read-only over local files)\n 'search_codebase',\n 'extract_symbols',\n // Repo analysis (read-only)\n 'repo_analyze',\n 'repo_security_plan',\n // Routing recommendation (no side effects — returns recommendation)\n 'delegate_to_model',\n // Registry import (returns a draft template — does not write)\n 'registry_import',\n]);\n\n/**\n * Returns true if the tool is risky under confirm_risky mode (default-deny\n * for unknown tools — security layer fails closed).\n */\nexport function isRiskyTool(toolName: string): boolean {\n return !READ_ONLY_TOOLS.has(toolName);\n}\n","/**\n * Access Constraint Deriver — Policy enforcement (#1977, #2279).\n *\n * Pure function that checks a proposed tool call against a derived policy\n * and returns an AccessDecision. Enforcement depends on the policy's mode:\n * - `off` and `audit` never block\n * - `confirm_risky` (#2279) blocks violations on risky tools (write/exec/\n * network) and log-and-allows violations on read-only tools\n * - `enforce` blocks every violation regardless of risk classification\n *\n * @module security/access-constraint-deriver/enforcer\n */\n\nimport { isPathDenied, isToolDenied } from './denylist.js';\nimport { isRiskyTool } from './tool-risk.js';\nimport type { AccessDecision, TaskAccessPolicy } from './types.js';\n\n/**\n * Checks a proposed tool call against the unbypassable denylist AND the\n * task's derived access policy.\n *\n * Order of operations (important — the denylist is FIRST and unbypassable):\n * 1. If the tool is on the hardcoded deny-tool list → deny regardless\n * of policy. This is unbypassable even in `off` mode.\n * 2. If a file-path argument is provided and matches an unbypassable path\n * pattern (e.g. `~/.ssh/**`, `/etc/shadow`) → deny regardless.\n * 3. Otherwise, fall back to the per-task policy (bypass in skeleton).\n *\n * The denylist check runs before the policy check so a malicious LLM-derived\n * policy cannot grant access to secrets/credentials by listing the tool in\n * `allowedTools`.\n */\nexport function checkAccess(\n toolName: string,\n policy: TaskAccessPolicy,\n args?: { readonly path?: string }\n): AccessDecision {\n // 1. Unbypassable tool denylist — applies in all modes.\n if (isToolDenied(toolName)) {\n return {\n decision: 'deny',\n reason: `tool \"${toolName}\" is on the unbypassable deny-tool list`,\n matchedRule: 'unbypassable:tool',\n };\n }\n\n // 2. Unbypassable path denylist — applies when a path argument is given.\n if (typeof args?.path === 'string' && args.path.length > 0 && isPathDenied(args.path)) {\n return {\n decision: 'deny',\n reason: `path \"${args.path}\" is on the unbypassable deny-path list`,\n matchedRule: 'unbypassable:path',\n };\n }\n\n // 3. Per-task policy check.\n if (policy.allowedTools === '*') return { decision: 'allow' };\n\n if (policy.allowedTools.includes(toolName)) return { decision: 'allow' };\n\n return decideOnViolation(toolName, policy.mode);\n}\n\n/**\n * Mode-specific behavior when a tool is not in the per-task allowlist.\n * Extracted so checkAccess stays under the complexity-10 cap.\n */\nfunction decideOnViolation(toolName: string, mode: TaskAccessPolicy['mode']): AccessDecision {\n if (mode === 'audit') {\n return {\n decision: 'log-and-allow',\n warning: `tool \"${toolName}\" not in derived policy (audit mode)`,\n };\n }\n // confirm_risky: split by tool risk classification (#2279). Read-only\n // violations are log-and-allow (audit-like); risky violations are denied\n // with a structured reason that surfaces \"would-have-required-approval\"\n // semantics. Operators add the tool to the allowlist after review, or\n // graduate to `enforce` once the violation rate is acceptable.\n if (mode === 'confirm_risky') {\n if (!isRiskyTool(toolName)) {\n return {\n decision: 'log-and-allow',\n warning: `tool \"${toolName}\" not in derived policy (confirm_risky mode, read-only — would have required human approval, allowed because read-only)`,\n };\n }\n return {\n decision: 'deny',\n reason: `tool \"${toolName}\" not in derived policy (confirm_risky mode, risky — would have required human approval; denied for now, add to allowedTools or run in audit mode to allow)`,\n matchedRule: 'allowedTools:confirm_risky',\n };\n }\n return {\n decision: 'deny',\n reason: `tool \"${toolName}\" not in derived policy`,\n matchedRule: 'allowedTools',\n };\n}\n","/**\n * Access Constraint Deriver — MCP tool dispatch guard (#1977 final wiring).\n *\n * Per-call helper and middleware factory that plugs the access-constraint\n * enforcer into the MCP tool dispatch path. Runs AFTER policy derivation\n * (deriver.ts owns that) and BEFORE the tool handler executes.\n *\n * Behavior matrix:\n * - mode=off → no-op, allows every call (this is the default; runtime\n * behavior is unchanged from pre-#1977)\n * - mode=audit → checks against the policy; on violation, logs a warning\n * and still forwards to the handler\n * - mode=enforce → checks against the policy; on violation, returns an\n * MCP-format isError result without invoking the handler\n *\n * The enforcer's hardcoded denylist (denylist.ts) runs FIRST regardless\n * of mode. Even `off` mode denies destructive tools and secret paths.\n *\n * @module security/access-constraint-deriver/mcp-guard\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { checkAccess } from './enforcer.js';\nimport type { AccessDecision, TaskAccessPolicy } from './types.js';\n\n/** AsyncLocalStorage holding the active task's access policy. */\nconst accessPolicyStorage = new AsyncLocalStorage<TaskAccessPolicy>();\n\n/**\n * Run `fn` with `policy` available to any nested MCP tool dispatch.\n *\n * Orchestrators (orchestrate, execute_expert, etc.) derive a policy at\n * task start and wrap downstream work in this helper. Tool handlers that\n * use `guardMcpToolCall` will read the policy from ALS.\n */\nexport function withAccessPolicy<T>(policy: TaskAccessPolicy, fn: () => Promise<T>): Promise<T> {\n return accessPolicyStorage.run(policy, fn);\n}\n\n/**\n * Returns the active access policy, or undefined if no wrapping `withAccessPolicy`\n * is in scope. When undefined, `guardMcpToolCall` treats the request as\n * mode=off (permissive) since no task context has been established.\n */\nexport function getActivePolicy(): TaskAccessPolicy | undefined {\n return accessPolicyStorage.getStore();\n}\n\n/**\n * Input-hints a tool handler can surface so the guard can reason about\n * file-path arguments. Tools with a `path` arg should pass it; tools\n * without can omit.\n */\nexport interface GuardArgs {\n readonly path?: string;\n}\n\n/**\n * Check a proposed MCP tool call against the active access policy.\n *\n * Pure function — does not mutate the policy or the storage. Returns an\n * AccessDecision the caller interprets:\n *\n * - `allow`: invoke the handler\n * - `deny`: do not invoke; return a RefuseAction / isError result upstream\n * - `log-and-allow`: log a warning, then invoke the handler (audit mode)\n *\n * When no policy is in ALS (no wrapping `withAccessPolicy`), this returns\n * `allow` — the guard is opt-in at the orchestrator layer.\n */\nexport function guardMcpToolCall(toolName: string, args?: GuardArgs): AccessDecision {\n const policy = getActivePolicy();\n if (policy === undefined) return { decision: 'allow' };\n return checkAccess(toolName, policy, args);\n}\n\n/**\n * Shape of the logger the middleware uses. Minimal to avoid coupling.\n */\ninterface MiddlewareLogger {\n warn: (message: string, context?: Record<string, unknown>) => void;\n info: (message: string, context?: Record<string, unknown>) => void;\n}\n\n/**\n * Formats a deny decision as an MCP-compliant isError ToolResult shape.\n * The MCP server's middleware chain recognizes `{ isError, content }` and\n * surfaces it as a tool error to the caller.\n */\nexport function denyToToolResult(\n decision: Extract<AccessDecision, { decision: 'deny' }>,\n requestId: string\n): { isError: true; content: Array<{ type: 'text'; text: string }> } {\n return {\n isError: true,\n content: [\n {\n type: 'text',\n text: `access denied: ${decision.reason} (rule: ${decision.matchedRule}, request: ${requestId})`,\n },\n ],\n };\n}\n\n/**\n * Create an access-policy middleware that plugs into the MCP middleware\n * chain. Reads the active policy from ALS. When no policy is active OR\n * the policy is in `off` mode, this middleware is a no-op pass-through.\n */\nexport function createAccessPolicyMiddleware(config: {\n readonly toolName: string;\n readonly logger: MiddlewareLogger;\n}): (\n args: unknown,\n ctx: { readonly requestContext: { readonly requestId: string } },\n next: (args: unknown, ctx: unknown) => Promise<unknown>\n) => Promise<unknown> {\n return async (args, ctx, next) => {\n const policy = getActivePolicy();\n if (policy === undefined || policy.mode === 'off') {\n return next(args, ctx);\n }\n\n const guardArgs = toGuardArgs(args);\n const decision = checkAccess(config.toolName, policy, guardArgs);\n\n if (decision.decision === 'allow') {\n return next(args, ctx);\n }\n if (decision.decision === 'log-and-allow') {\n config.logger.warn('access-policy: audit violation', {\n tool: config.toolName,\n warning: decision.warning,\n policySource: policy.source,\n requestId: ctx.requestContext.requestId,\n });\n return next(args, ctx);\n }\n // decision.decision === 'deny'\n config.logger.info('access-policy: tool call denied', {\n tool: config.toolName,\n reason: decision.reason,\n matchedRule: decision.matchedRule,\n policySource: policy.source,\n mode: policy.mode,\n requestId: ctx.requestContext.requestId,\n });\n return denyToToolResult(decision, ctx.requestContext.requestId);\n };\n}\n\n/** Extract path from a typed tool-arg record, if present and a string. */\nfunction toGuardArgs(args: unknown): GuardArgs | undefined {\n if (typeof args !== 'object' || args === null) return undefined;\n const path = (args as Record<string, unknown>)['path'];\n return typeof path === 'string' && path.length > 0 ? { path } : undefined;\n}\n","/**\n * Access Constraint Deriver — MCP middleware-chain adapter (#1977 activation).\n *\n * Bridges `createAccessPolicyMiddleware` (which returns a generic\n * `Promise<unknown>`-shaped middleware) to the strongly-typed `Middleware`\n * contract used by `mcp/middleware/middleware-chain.ts`.\n *\n * Mounted into the standard middleware stack so every tool call passes\n * through the ClawGuard enforcer. When no orchestrator has wrapped the\n * call with `withAccessPolicy(...)`, this adapter is a no-op pass-through\n * — runtime behavior is unchanged for callers that don't set up a policy.\n *\n * @module security/access-constraint-deriver/chain-adapter\n */\n\nimport { checkAccess } from './enforcer.js';\nimport { denyToToolResult, getActivePolicy } from './mcp-guard.js';\nimport type { GuardArgs } from './mcp-guard.js';\n// Type-only import: no runtime cycle with mcp/middleware/middleware-chain.ts.\nimport type { Middleware } from '../../mcp/middleware/middleware-chain.js';\n\nfunction toGuardArgs(args: unknown): GuardArgs | undefined {\n if (typeof args !== 'object' || args === null) return undefined;\n const path = (args as Record<string, unknown>)['path'];\n return typeof path === 'string' && path.length > 0 ? { path } : undefined;\n}\n\n/**\n * Builds a middleware-chain-compatible access-policy middleware for\n * `toolName`. Reads the active `TaskAccessPolicy` from `AsyncLocalStorage`\n * (populated by `withAccessPolicy`). When no policy is active OR the\n * policy is in `off` mode, the middleware is a no-op pass-through.\n */\nexport function createAccessPolicyChainMiddleware(toolName: string): Middleware {\n return async (args, ctx, next) => {\n const policy = getActivePolicy();\n if (policy === undefined || policy.mode === 'off') {\n return next(args, ctx);\n }\n\n const decision = checkAccess(toolName, policy, toGuardArgs(args));\n\n if (decision.decision === 'allow') {\n return next(args, ctx);\n }\n if (decision.decision === 'log-and-allow') {\n ctx.logger.warn('access-policy: audit violation', {\n tool: toolName,\n warning: decision.warning,\n policySource: policy.source,\n requestId: ctx.requestContext.requestId,\n });\n return next(args, ctx);\n }\n ctx.logger.info('access-policy: tool call denied', {\n tool: toolName,\n reason: decision.reason,\n matchedRule: decision.matchedRule,\n policySource: policy.source,\n mode: policy.mode,\n requestId: ctx.requestContext.requestId,\n });\n return denyToToolResult(decision, ctx.requestContext.requestId);\n };\n}\n","/**\n * nexus-agents/mcp - Centralized Middleware Chain\n *\n * Provides a composable middleware chain for MCP tools with guaranteed\n * execution order: auth → validation → policy → rate-limit → timeout → audit\n *\n * @module mcp/middleware/middleware-chain\n * (Source: Issue #189 - Centralized MCP middleware chain)\n */\n\nimport type { z } from 'zod';\nimport type { ILogger } from '../../core/index.js';\nimport { createLogger, getTimeProvider } from '../../core/index.js';\nimport { validateToolInput } from './validation.js';\nimport { RateLimiter, type RateLimiterConfig } from './rate-limiter.js';\nimport { type IPolicyFirewall, type ExecutionMode, createPolicyContext } from './policy.js';\nimport { TimeoutGuard, type TimeoutGuardConfig } from './timeout-guard.js';\nimport { MCP_TIMEOUTS } from '../../config/timeouts.js';\nimport { createRequestContext, contextForLogging, type RequestContext } from './request-context.js';\nimport { createMetricsMiddleware } from './tool-metrics.js';\nimport { abortSignalStorage } from '../mcp-notifier.js';\nimport { createAccessPolicyChainMiddleware } from '../../security/access-constraint-deriver/chain-adapter.js';\nimport { toolStructuredError } from '../tools/tool-result.js';\nimport type { ErrorCategory } from '../error-envelope.js';\n\n/**\n * MCP tool result type.\n *\n * This interface is structurally compatible with the MCP SDK's CallToolResult.\n * The content array accepts text content for simplicity, while remaining\n * compatible with the SDK's broader ContentBlock type at runtime.\n */\nexport interface ToolResult {\n /** Content blocks returned by the tool (text content) */\n content: Array<{ type: 'text'; text: string }>;\n /** Whether this represents an error result */\n isError?: boolean;\n /** Structured output for SDK outputSchema validation (Issue #1117) */\n structuredContent?: Record<string, unknown>;\n /** Out-of-band metadata — carries the #2649 error envelope on errors. */\n _meta?: Record<string, unknown>;\n}\n\n/**\n * Middleware context passed through the chain.\n */\nexport interface MiddlewareContext {\n /** Unique request ID for tracing */\n readonly requestContext: RequestContext;\n /** Logger with request context */\n readonly logger: ILogger;\n /** Validated arguments (set after validation middleware) */\n validatedArgs?: unknown;\n}\n\n/**\n * Middleware function signature.\n * Each middleware receives the context and a next function to call.\n */\nexport type Middleware = (\n args: unknown,\n ctx: MiddlewareContext,\n next: (args: unknown, ctx: MiddlewareContext) => Promise<ToolResult>\n) => Promise<ToolResult>;\n\n/**\n * Configuration for the middleware chain.\n */\nexport interface MiddlewareChainConfig {\n /** Tool name for logging and policy evaluation */\n toolName: string;\n /** Zod schema for input validation (optional) */\n schema?: z.ZodType;\n /** Policy firewall instance (optional) */\n policyFirewall?: IPolicyFirewall | undefined;\n /** Execution mode for policy evaluation */\n executionMode?: ExecutionMode | undefined;\n /** Allowed paths for file operations */\n allowedPaths?: readonly string[] | undefined;\n /** Rate limiter configuration (optional) */\n rateLimiter?: RateLimiterConfig | RateLimiter | undefined;\n /** Timeout configuration (optional) */\n timeout?: TimeoutGuardConfig | undefined;\n /** Logger instance (optional) */\n logger?: ILogger | undefined;\n /** Skip specific middleware steps */\n skip?: MiddlewareSkipConfig | undefined;\n}\n\n/**\n * Configuration for skipping middleware steps.\n */\nexport interface MiddlewareSkipConfig {\n validation?: boolean | undefined;\n policy?: boolean | undefined;\n rateLimit?: boolean | undefined;\n timeout?: boolean | undefined;\n audit?: boolean | undefined;\n /** Skip the ClawGuard access-policy middleware (#1977). */\n accessPolicy?: boolean | undefined;\n}\n\n/**\n * Tool handler function signature.\n */\nexport type ToolHandler = (args: unknown) => Promise<ToolResult>;\n\n/**\n * Context-aware handler that receives middleware context.\n */\nexport type ContextAwareToolHandler = (\n args: unknown,\n ctx: MiddlewareContext\n) => Promise<ToolResult>;\n\n/**\n * Creates an error result with the structured error envelope (#2649).\n * Each middleware passes the category that matches its failure mode.\n */\nfunction errorResult(category: ErrorCategory, message: string, requestId: string): ToolResult {\n return toolStructuredError({\n errorCategory: category,\n message: `${message} (request: ${requestId})`,\n });\n}\n\n/**\n * Creates validation middleware.\n */\nfunction createValidationMiddleware(schema: z.ZodType): Middleware {\n return async (args, ctx, next) => {\n const result = validateToolInput(schema, args);\n if (!result.ok) {\n ctx.logger.warn('Validation failed', {\n error: result.error.message,\n });\n return errorResult(\n 'validation',\n `Validation error: ${result.error.message}`,\n ctx.requestContext.requestId\n );\n }\n ctx.validatedArgs = result.value;\n return next(result.value, ctx);\n };\n}\n\n/**\n * Creates policy middleware.\n */\nfunction createPolicyMiddleware(\n firewall: IPolicyFirewall,\n toolName: string,\n mode: ExecutionMode,\n allowedPaths?: readonly string[]\n): Middleware {\n return async (args, ctx, next) => {\n const policyCtx = createPolicyContext(toolName, args, {\n mode,\n ...(allowedPaths !== undefined && { allowedPaths }),\n });\n const decision = firewall.evaluate(policyCtx);\n\n if (!decision.allowed) {\n ctx.logger.warn('Policy denied', {\n reason: decision.reason,\n ruleName: decision.ruleName,\n });\n return errorResult(\n 'permission',\n `Policy denied: ${decision.reason}`,\n ctx.requestContext.requestId\n );\n }\n ctx.logger.debug('Policy check passed', { reason: decision.reason });\n return next(args, ctx);\n };\n}\n\n/**\n * Creates rate limit middleware.\n */\nfunction createRateLimitMiddleware(limiter: RateLimiter): Middleware {\n return async (args, ctx, next) => {\n const acquired = limiter.tryAcquire();\n if (!acquired) {\n const state = limiter.getState();\n ctx.logger.warn('Rate limit exceeded', {\n nextTokenMs: state.nextTokenMs,\n });\n return errorResult(\n 'transient',\n `Rate limit exceeded. Try again in ${String(state.nextTokenMs)}ms`,\n ctx.requestContext.requestId\n );\n }\n return next(args, ctx);\n };\n}\n\n/**\n * Creates timeout middleware.\n * Reads AbortSignal from AsyncLocalStorage for client cancellation support.\n */\nfunction createTimeoutMiddleware(guard: TimeoutGuard, toolName: string): Middleware {\n return async (args, ctx, next) => {\n const signal = abortSignalStorage.getStore();\n const result = await guard.execute(() => next(args, ctx), {\n operationName: toolName,\n ...(signal !== undefined ? { signal } : {}),\n });\n\n if (!result.ok) {\n ctx.logger.error('Operation timed out', undefined, {\n code: result.error.code,\n timeoutMs: result.error.timeoutMs,\n });\n // #3726 discoverability: append the per-tool hint (e.g. \"retry in async\n // job-mode\") so a sync long-running tool that hits its ceiling tells the\n // caller how to escape it. Absent hint → message unchanged.\n const hint = MCP_TIMEOUTS.perToolTimeoutHint[toolName];\n const message = hint !== undefined ? `${result.error.message} ${hint}` : result.error.message;\n // Timeout — transient, a retry with more headroom may succeed.\n return errorResult('transient', message, ctx.requestContext.requestId);\n }\n\n if (result.value.nearTimeout) {\n ctx.logger.warn('Operation completed near timeout threshold', {\n durationMs: result.value.durationMs,\n });\n }\n\n return result.value.value;\n };\n}\n\n/**\n * Creates audit middleware that logs start/end of request.\n */\nfunction createAuditMiddleware(): Middleware {\n return async (args, ctx, next) => {\n const startTime = getTimeProvider().now();\n ctx.logger.info('Tool invocation started');\n\n try {\n const result = await next(args, ctx);\n const durationMs = getTimeProvider().now() - startTime;\n\n if (result.isError === true) {\n ctx.logger.warn('Tool execution completed with error', { durationMs });\n } else {\n ctx.logger.info('Tool execution completed', { durationMs });\n }\n return result;\n } catch (error) {\n const durationMs = getTimeProvider().now() - startTime;\n const message = error instanceof Error ? error.message : 'Unknown error';\n ctx.logger.error('Tool execution failed', error instanceof Error ? error : undefined, {\n durationMs,\n });\n return errorResult('internal', `Internal error: ${message}`, ctx.requestContext.requestId);\n }\n };\n}\n\n/**\n * Composes multiple middleware functions into a single chain.\n */\nfunction composeMiddleware(middlewares: Middleware[]): Middleware {\n return (args, ctx, finalHandler) => {\n const dispatch = (index: number, currentArgs: unknown): Promise<ToolResult> => {\n if (index >= middlewares.length) {\n return finalHandler(currentArgs, ctx);\n }\n const middleware = middlewares[index];\n if (middleware === undefined) {\n return finalHandler(currentArgs, ctx);\n }\n return middleware(currentArgs, ctx, (nextArgs) => dispatch(index + 1, nextArgs));\n };\n return dispatch(0, args);\n };\n}\n\n/** Helper: adds audit middleware if not skipped */\nfunction addAuditMiddleware(middlewares: Middleware[], skip: MiddlewareSkipConfig): void {\n if (skip.audit !== true) {\n middlewares.push(createAuditMiddleware());\n }\n}\n\n/** Helper: adds rate limit middleware if configured */\nfunction addRateLimitMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.rateLimit !== true && config.rateLimiter !== undefined) {\n const limiter =\n config.rateLimiter instanceof RateLimiter\n ? config.rateLimiter\n : new RateLimiter(config.rateLimiter);\n middlewares.push(createRateLimitMiddleware(limiter));\n }\n}\n\n/** Helper: adds validation middleware if schema provided */\nfunction addValidationMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.validation !== true && config.schema !== undefined) {\n middlewares.push(createValidationMiddleware(config.schema));\n }\n}\n\n/** Helper: adds policy middleware if configured */\nfunction addPolicyMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.policy !== true && config.policyFirewall !== undefined) {\n const mode = config.executionMode ?? 'read-only';\n middlewares.push(\n createPolicyMiddleware(config.policyFirewall, config.toolName, mode, config.allowedPaths)\n );\n }\n}\n\n/** Helper: adds timeout middleware if configured */\nfunction addTimeoutMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.timeout !== true && config.timeout !== undefined) {\n const guard = new TimeoutGuard(config.timeout);\n middlewares.push(createTimeoutMiddleware(guard, config.toolName));\n }\n}\n\n/**\n * Helper: adds the ClawGuard access-policy middleware (#1977).\n *\n * Always added unless explicitly skipped. The middleware is ALS-backed\n * and a no-op pass-through when no orchestrator has called\n * `withAccessPolicy(...)` — so runtime behavior is unchanged for callers\n * that haven't opted in.\n */\nfunction addAccessPolicyMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.accessPolicy !== true) {\n middlewares.push(createAccessPolicyChainMiddleware(config.toolName));\n }\n}\n\n/** Helper: builds the middleware stack */\nfunction buildMiddlewareStack(config: MiddlewareChainConfig): Middleware[] {\n const skip = config.skip ?? {};\n const middlewares: Middleware[] = [];\n\n middlewares.push(createMetricsMiddleware()); // Tool usage analytics (#1022)\n addAuditMiddleware(middlewares, skip);\n addRateLimitMiddleware(middlewares, config, skip);\n addValidationMiddleware(middlewares, config, skip);\n addPolicyMiddleware(middlewares, config, skip);\n addAccessPolicyMiddleware(middlewares, config, skip); // #1977 ClawGuard\n addTimeoutMiddleware(middlewares, config, skip);\n\n return middlewares;\n}\n\n/**\n * Creates a middleware chain with the standard execution order.\n *\n * Order: audit → rate-limit → validation → policy → timeout → handler\n *\n * Audit wraps everything to capture timing. Rate limit is checked early\n * to reject requests before expensive validation. Timeout wraps the\n * actual handler execution.\n *\n * @param config - Chain configuration\n * @returns A function that wraps handlers with the middleware chain\n */\nexport function createMiddlewareChain(\n config: MiddlewareChainConfig\n): (handler: ContextAwareToolHandler) => ToolHandler {\n const logger = config.logger ?? createLogger({ tool: config.toolName });\n const middlewares = buildMiddlewareStack(config);\n const composed = composeMiddleware(middlewares);\n\n return (handler: ContextAwareToolHandler): ToolHandler => {\n return async (args: unknown): Promise<ToolResult> => {\n const requestContext = createRequestContext({ toolName: config.toolName });\n const requestLogger = logger.child(contextForLogging(requestContext));\n const ctx: MiddlewareContext = { requestContext, logger: requestLogger };\n return composed(args, ctx, (finalArgs, finalCtx) => handler(finalArgs, finalCtx));\n };\n };\n}\n\n/**\n * Convenience function to wrap a handler with default middleware.\n *\n * @param toolName - Name of the tool\n * @param handler - The tool handler\n * @param options - Optional middleware configuration\n * @returns Wrapped handler with middleware\n */\nexport function withMiddleware(\n toolName: string,\n handler: ContextAwareToolHandler | ToolHandler,\n options?: Partial<Omit<MiddlewareChainConfig, 'toolName'>>\n): ToolHandler {\n // Note: Policy firewall is NOT added by default - must be explicitly configured\n // This follows the principle of minimal defaults with explicit opt-in for security\n const config: MiddlewareChainConfig = {\n toolName,\n ...options,\n };\n\n const chain = createMiddlewareChain(config);\n\n // Wrap handler to support both signatures\n const wrappedHandler: ContextAwareToolHandler = (args, ctx) => {\n // Check if handler expects context (2 params)\n if (handler.length >= 2) {\n return handler(args, ctx);\n }\n return (handler as ToolHandler)(args);\n };\n\n return chain(wrappedHandler);\n}\n\n/**\n * Creates a middleware chain factory with shared configuration.\n *\n * @param sharedConfig - Configuration shared across all tools\n * @returns Factory function for creating wrapped handlers\n */\nexport function createMiddlewareFactory(\n sharedConfig: Omit<MiddlewareChainConfig, 'toolName' | 'schema'>\n): (\n toolName: string,\n handler: ContextAwareToolHandler | ToolHandler,\n schema?: z.ZodType\n) => ToolHandler {\n return (toolName, handler, schema) => {\n const options = schema !== undefined ? { ...sharedConfig, schema } : sharedConfig;\n return withMiddleware(toolName, handler, options);\n };\n}\n","/* eslint-disable max-lines -- Cohesive central registry: per-tool annotation entries grow with REGISTERED_TOOLS (governance: 400-600 OK if cohesive). */\n/**\n * MCP Tool Annotations Registry\n *\n * Centralized side effect and behavior annotations for all MCP tools.\n * Uses MCP protocol-standard ToolAnnotations (readOnlyHint, destructiveHint,\n * idempotentHint, openWorldHint) plus custom side effect metadata.\n *\n * @module mcp/tools/tool-annotations\n * (Source: Issue #993 — Document MCP tool side effects in schema metadata)\n */\n\n/**\n * Side effect category per Issue #993 proposal.\n * - explicit: Intended, documented state changes\n * - implicit: System-level effects (rate limits, token consumption)\n * - coupling: Modifies state that another tool depends on\n */\nexport type SideEffectCategory = 'explicit' | 'implicit' | 'coupling';\n\n/**\n * A single side effect declaration.\n */\nexport interface SideEffect {\n readonly category: SideEffectCategory;\n readonly description: string;\n}\n\n/**\n * MCP protocol-standard tool annotations.\n * Maps to ToolAnnotationsSchema from @modelcontextprotocol/sdk.\n */\nexport interface ToolAnnotations {\n /** Human-readable title for the tool */\n readonly title?: string;\n /** If true, the tool does not modify state */\n readonly readOnlyHint?: boolean;\n /** If true, the tool may perform destructive operations */\n readonly destructiveHint?: boolean;\n /** If true, calling with same args yields same result */\n readonly idempotentHint?: boolean;\n /** If true, the tool interacts with external systems */\n readonly openWorldHint?: boolean;\n}\n\n/**\n * Combined tool metadata: MCP annotations + custom side effects.\n */\nexport interface ToolSideEffectsEntry {\n readonly annotations: ToolAnnotations;\n readonly sideEffects: readonly SideEffect[];\n}\n\n/**\n * Canonical registry of tool annotations and side effects.\n * One entry per registered MCP tool.\n */\nexport const TOOL_ANNOTATIONS: Readonly<Record<string, ToolSideEffectsEntry>> = {\n run: {\n annotations: {\n title: 'Run (Adaptive Entry Point)',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [\n { category: 'implicit', description: 'Records a routing decision for observability' },\n ],\n },\n delegate_to_model: {\n annotations: {\n title: 'Delegate to Model',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Consumes rate limit quota' }],\n },\n orchestrate: {\n annotations: {\n title: 'Orchestrate Task',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Creates and executes expert agents' },\n { category: 'implicit', description: 'Consumes API tokens from configured provider' },\n { category: 'coupling', description: 'May trigger rate limiting on model adapter' },\n { category: 'coupling', description: 'Records task outcome in OutcomeFeedbackCollector' },\n ],\n },\n create_expert: {\n annotations: {\n title: 'Create Expert',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n sideEffects: [\n { category: 'explicit', description: 'Creates expert agent in shared registry' },\n { category: 'coupling', description: 'Expert ID required by execute_expert' },\n ],\n },\n execute_expert: {\n annotations: {\n title: 'Execute Expert',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Executes expert agent task via model adapter' },\n { category: 'implicit', description: 'Consumes API tokens from configured provider' },\n { category: 'coupling', description: 'Requires expert created by create_expert' },\n { category: 'coupling', description: 'May trigger rate limiting on model adapter' },\n ],\n },\n run_workflow: {\n annotations: {\n title: 'Run Workflow',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Executes multi-step workflow template' },\n { category: 'implicit', description: 'Consumes API tokens if workflow uses model adapter' },\n { category: 'coupling', description: 'May trigger rate limiting on model adapter' },\n ],\n },\n list_experts: {\n annotations: {\n title: 'List Experts',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Consumes rate limit quota' }],\n },\n list_workflows: {\n annotations: {\n title: 'List Workflows',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Consumes rate limit quota' }],\n },\n consensus_vote: {\n annotations: {\n title: 'Consensus Vote',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Executes multi-agent voting across CLIs' },\n { category: 'implicit', description: 'Consumes API tokens from multiple providers' },\n { category: 'coupling', description: 'Records vote outcomes for weather report' },\n ],\n },\n research_query: {\n annotations: {\n title: 'Research Query',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Consumes rate limit quota' }],\n },\n research_add: {\n annotations: {\n title: 'Research Add',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Adds paper to research registry on disk' },\n { category: 'implicit', description: 'Fetches metadata from arXiv API' },\n ],\n },\n research_discover: {\n annotations: {\n title: 'Research Discover',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'implicit', description: 'Queries external APIs (arXiv, GitHub, etc.)' },\n { category: 'coupling', description: 'Auto-catalogs discovered references' },\n ],\n },\n survey_oss_landscape: {\n annotations: {\n title: 'Survey OSS Landscape',\n readOnlyHint: true,\n destructiveHint: false,\n // Same query may return different results day-to-day as star counts\n // and last-commit dates evolve; idempotentHint=false matches reality.\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [{ category: 'implicit', description: 'Queries the GitHub search API' }],\n },\n vendor_publishing_audit: {\n annotations: {\n title: 'Vendor Publishing Audit',\n readOnlyHint: true,\n destructiveHint: false,\n // Pure static lookup against the in-process seed dataset.\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Consumes rate limit quota' }],\n },\n compare_data_feeds: {\n annotations: {\n title: 'Compare Data Feeds',\n readOnlyHint: true,\n destructiveHint: false,\n // Same input → same output; pure file diff with no external calls.\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Reads two files from the workspace' }],\n },\n research_analyze: {\n annotations: {\n title: 'Research Analyze',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Consumes rate limit quota' }],\n },\n research_catalog_review: {\n annotations: {\n title: 'Research Catalog Review',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n sideEffects: [\n { category: 'explicit', description: 'Approves or dismisses cataloged references' },\n { category: 'coupling', description: 'Approved items added to research registry' },\n ],\n },\n memory_query: {\n annotations: {\n title: 'Memory Query',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n sideEffects: [\n { category: 'implicit', description: 'Consumes rate limit quota' },\n { category: 'implicit', description: 'May trigger reflective retrieval (MemR3)' },\n ],\n },\n memory_stats: {\n annotations: {\n title: 'Memory Stats',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Consumes rate limit quota' }],\n },\n memory_write: {\n annotations: {\n title: 'Memory Write',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n sideEffects: [\n { category: 'explicit', description: 'Writes data to memory backend' },\n { category: 'implicit', description: 'Consumes rate limit quota' },\n ],\n },\n weather_report: {\n annotations: {\n title: 'Weather Report',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Consumes rate limit quota' }],\n },\n improvement_review: {\n annotations: {\n title: 'Improvement Review',\n readOnlyHint: false,\n destructiveHint: false,\n // When fileIssues=true, creates GitHub issues — not idempotent.\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'implicit', description: 'Reads OutcomeStore and runs fitness audit' },\n {\n category: 'explicit',\n description: 'When fileIssues=true, files candidate GitHub issues via gh CLI',\n },\n { category: 'implicit', description: 'Consumes rate limit quota' },\n ],\n },\n run_quality_gate: {\n annotations: {\n title: 'Run Quality Gate',\n // Spawns build/test toolchains which can write artifacts — not read-only.\n readOnlyHint: false,\n destructiveHint: false,\n // Same checks against the same code yield the same verdict.\n idempotentHint: true,\n // build/test/security invoke local toolchains and may reach the network.\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'implicit',\n description:\n 'Spawns local toolchain processes (tsc/eslint/vitest/build) in the target project dir',\n },\n {\n category: 'implicit',\n description: 'build/test checks may write build artifacts and coverage output to disk',\n },\n ],\n },\n issue_triage: {\n annotations: {\n title: 'Issue Triage',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'implicit', description: 'Fetches issue data from GitHub API' },\n { category: 'implicit', description: 'Consumes rate limit quota' },\n ],\n },\n run_graph_workflow: {\n annotations: {\n title: 'Run Graph Workflow',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Executes graph-based workflow with checkpointing' },\n { category: 'implicit', description: 'Writes checkpoint files to disk' },\n { category: 'coupling', description: 'May trigger rate limiting on model adapters' },\n ],\n },\n execute_spec: {\n annotations: {\n title: 'Execute Spec',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Parses and executes markdown specification' },\n { category: 'implicit', description: 'Consumes API tokens from configured provider' },\n { category: 'implicit', description: 'Writes execution trace to disk' },\n ],\n },\n registry_import: {\n annotations: {\n title: 'Registry Import',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'explicit', description: 'Generates draft model registry entry' }],\n },\n query_trace: {\n annotations: {\n title: 'Query Trace',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [\n { category: 'implicit', description: 'Reads execution trace JSONL files from disk' },\n ],\n },\n repo_analyze: {\n annotations: {\n title: 'Repo Analyze',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'implicit',\n description: 'Fetches repository metadata from GitHub API via gh CLI',\n },\n { category: 'implicit', description: 'Consumes rate limit quota' },\n ],\n },\n repo_security_plan: {\n annotations: {\n title: 'Repo Security Plan',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'implicit',\n description: 'Fetches repository metadata from GitHub API via gh CLI',\n },\n { category: 'implicit', description: 'Consumes rate limit quota' },\n ],\n },\n research_add_source: {\n annotations: {\n title: 'Research Add Source',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Adds a non-paper source to the research registry' },\n { category: 'coupling', description: 'New entries affect research_discover/research_query' },\n ],\n },\n research_synthesize: {\n annotations: {\n title: 'Research Synthesize',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Reads research catalog + alignment map' }],\n },\n query_task_state: {\n annotations: {\n title: 'Query Task State',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [\n { category: 'implicit', description: 'Reads the structured task-state log (#2278)' },\n ],\n },\n get_job_result: {\n annotations: {\n title: 'Get Job Result',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [\n {\n category: 'implicit',\n description: 'Reads the async-mode job-result sidecar (#3042 / epic #2631)',\n },\n ],\n },\n list_jobs: {\n annotations: {\n title: 'List Jobs',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [\n {\n category: 'implicit',\n description:\n 'Lists async-mode job summaries from the sidecar dir (#3046 / epic #2631 Stage 5)',\n },\n ],\n },\n cancel_job: {\n annotations: {\n title: 'Cancel Job',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [\n {\n category: 'explicit',\n description: 'Writes cancellation record to the async-mode sidecar (#3042 Stage 1b)',\n },\n {\n category: 'coupling',\n description:\n 'Triggers AbortSignal unwind in same-process dispatcher (cross-process workers must poll)',\n },\n ],\n },\n verify_audit_chain: {\n annotations: {\n title: 'Verify Audit Chain',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [\n {\n category: 'implicit',\n description: 'Reads the immutable audit log and verifies the hash chain',\n },\n ],\n },\n ci_health_check: {\n annotations: {\n // #3530: NOT read-only / idempotent — every call appends a CI-health\n // telemetry event (appendCiHealthEvent in ci-health-check-tool.ts), which\n // both writes local state and accumulates per call. The check itself only\n // reads upstream, but the per-call telemetry append is a real side effect.\n title: 'CI Health Check',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n // Outbound network to githubstatus.com + GitHub API.\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'implicit',\n description:\n 'Fetches GitHub status-page + repo actions/runs to assess CI infrastructure health (#3076)',\n },\n {\n category: 'implicit',\n description: 'Appends a local CI-health telemetry event per call for observability (#3530)',\n },\n ],\n },\n extract_symbols: {\n annotations: {\n title: 'Extract Symbols',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [{ category: 'implicit', description: 'Reads source files and walks their ASTs' }],\n },\n search_codebase: {\n annotations: {\n title: 'Search Codebase',\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n },\n sideEffects: [\n {\n category: 'implicit',\n description: 'Reads source files and builds an in-memory symbol index',\n },\n ],\n },\n run_dev_pipeline: {\n annotations: {\n title: 'Run Dev Pipeline',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'explicit',\n description: 'Executes the V2 dev pipeline (delegates to CLI adapters)',\n },\n {\n category: 'implicit',\n description: 'Consumes API tokens; persists outcomes and checkpoints',\n },\n {\n category: 'coupling',\n description: 'Writes routing/learning state consumed by future runs',\n },\n ],\n },\n run_pipeline: {\n annotations: {\n title: 'Run Pipeline',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n { category: 'explicit', description: 'Executes a generic V2 pipeline TaskContract' },\n { category: 'implicit', description: 'Consumes API tokens; emits pipeline events' },\n { category: 'coupling', description: 'Writes policy/audit state consumed by other tools' },\n ],\n },\n pr_review: {\n annotations: {\n title: 'PR Review',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'explicit',\n description: 'Runs multi-voter PR review with verification gate (#2233)',\n },\n { category: 'implicit', description: 'Consumes API tokens across voter CLIs' },\n { category: 'coupling', description: 'Records voter outcomes for weather report' },\n ],\n },\n suggest_research_tasks: {\n annotations: {\n title: 'Suggest Research Tasks',\n // SUGGEST-ONLY: discovers/reads via research_discover and returns\n // candidate tasks. Files nothing, executes nothing, mutates nothing.\n readOnlyHint: true,\n destructiveHint: false,\n // Discovery results vary run-to-run as external sources evolve.\n idempotentHint: false,\n // Reaches external research APIs (arXiv/GitHub/etc.) via the engine.\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'implicit',\n description: 'Queries research_discover / external research APIs; consumes tokens',\n },\n ],\n },\n list_available_models: {\n annotations: {\n title: 'List Available Models',\n // Probes discovery transports and reports health. Reads only; mutates\n // nothing and does not change routing.\n readOnlyHint: true,\n destructiveHint: false,\n // Probe results vary as catalogs/CLIs change.\n idempotentHint: false,\n // Reaches the OpenRouter API + spawns CLI probes.\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'implicit',\n description: 'Fetches the OpenRouter catalog + probes CLI adapters (network/subprocess)',\n },\n ],\n },\n supply_chain_tradeoff_panel: {\n annotations: {\n title: 'Supply-chain Tradeoff Panel',\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n sideEffects: [\n {\n category: 'explicit',\n description:\n 'Runs per-axis tradeoff vote (build_time_determinism / supply_chain_risk / update_cadence) (#2294)',\n },\n { category: 'implicit', description: 'Consumes API tokens across voter CLIs' },\n { category: 'coupling', description: 'Records voter outcomes for weather report' },\n ],\n },\n};\n\n/**\n * Returns the annotations for a given tool, or undefined if not found.\n */\nexport function getToolAnnotations(toolName: string): ToolSideEffectsEntry | undefined {\n return TOOL_ANNOTATIONS[toolName];\n}\n\n/**\n * Returns only the MCP protocol annotations for a tool (for registerTool config).\n */\nexport function getMcpAnnotations(toolName: string): ToolAnnotations | undefined {\n return TOOL_ANNOTATIONS[toolName]?.annotations;\n}\n\n/**\n * Returns side effects for a tool filtered by category.\n */\nexport function getSideEffectsByCategory(\n toolName: string,\n category: SideEffectCategory\n): readonly SideEffect[] {\n const entry = TOOL_ANNOTATIONS[toolName];\n if (entry === undefined) return [];\n return entry.sideEffects.filter((se) => se.category === category);\n}\n","/**\n * Central per-tool MCP annotations accessors (#2648, Epic A; consolidated #3358).\n *\n * The MCP 2025-11-25 spec defines four boolean hints clients use to reason\n * about each tool's safety, retry semantics, and permission UX:\n *\n * - `readOnlyHint` — tool does not modify persistent state\n * - `destructiveHint` — tool can perform destructive operations\n * - `idempotentHint` — calling with the same input is safe to repeat\n * - `openWorldHint` — tool interacts with systems outside the server's control\n *\n * Per the MCP spec these are **hints**, not enforcement primitives — clients\n * should never trust them from an untrusted server. But for nexus-agents (a\n * governance substrate) the hints are load-bearing for:\n *\n * - Programmatic prerequisite gates (Epic B / #2652) — uses\n * `destructiveHint` and `openWorldHint` to decide what to gate.\n * - Retry policy decisions in pipeline runners — only retry tools where\n * `idempotentHint === true`.\n * - Permission-prompt UX consistency across Claude / Codex / Gemini /\n * OpenCode harnesses.\n *\n * The audit (#2648 / docs/research/nexus-agents-multi-harness-alignment-audit.md\n * §6 T14) requires **every** registered tool declare all four hints\n * explicitly — no defaults.\n *\n * **Single source of truth (#3358):** the per-tool annotation DATA lives in\n * the side-effects superset registry at `./tools/tool-annotations.ts`, where\n * each entry pairs the MCP hints (`.annotations`) with curated side-effects\n * metadata (#993). This file is the LIVE ACCESSOR path: each tool's\n * `registerTool()` call site reads its annotations via `getToolAnnotations(name)`.\n * Data flows data-file → accessor-file only (no circular import).\n *\n * @module mcp/tool-annotations\n */\n\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { TOOL_ANNOTATIONS as TOOL_SIDE_EFFECTS } from './tools/tool-annotations.js';\n\n/**\n * Look up the MCP annotations for a registered MCP tool. Throws if the tool\n * name isn't in the central registry — this enforces \"every tool declares its\n * hints explicitly\" rather than silently falling back to MCP's defaults\n * (which assume destructive + non-idempotent + open-world).\n *\n * The data is derived from the side-effects superset registry\n * (`./tools/tool-annotations.ts`, #993); only the four MCP hint booleans are\n * returned here — side-effects metadata is reached via that module's\n * `getSideEffectsByCategory`.\n */\nexport function getToolAnnotations(name: string): ToolAnnotations {\n const entry = TOOL_SIDE_EFFECTS[name];\n if (entry === undefined) {\n throw new Error(\n `getToolAnnotations: no entry for tool \"${name}\". Add it to TOOL_ANNOTATIONS in src/mcp/tools/tool-annotations.ts (#2648/#3358).`\n );\n }\n return entry.annotations;\n}\n","/**\n * nexus-agents/consensus - Core Type Definitions\n *\n * Core type definitions and Zod schemas for the consensus engine.\n * Supports multiple voting strategies for multi-agent decisions.\n */\n\nimport { z } from 'zod';\n\n/**\n * Consensus algorithm types.\n * - simple_majority: >50% of votes required\n * - supermajority: >=67% of votes required\n * - unanimous: 100% approval required\n * - proof_of_learning: weighted voting based on agent performance\n * - opinion_wise: higher-order voting with correlation awareness (Issue #333)\n * - higher_order: alias for opinion_wise (Issue #514)\n */\nexport const ConsensusAlgorithmSchema = z.enum([\n 'simple_majority',\n 'supermajority',\n 'unanimous',\n 'proof_of_learning',\n 'opinion_wise',\n 'higher_order',\n]);\nexport type ConsensusAlgorithm = z.infer<typeof ConsensusAlgorithmSchema>;\n\n/**\n * Vote decision options.\n */\nexport const VoteDecisionSchema = z.enum(['approve', 'reject', 'abstain']);\nexport type VoteDecision = z.infer<typeof VoteDecisionSchema>;\n\n/**\n * Proposal status in the lifecycle.\n */\nexport const ProposalStatusSchema = z.enum([\n 'pending',\n 'voting',\n 'approved',\n 'rejected',\n 'timeout',\n 'closed',\n]);\nexport type ProposalStatus = z.infer<typeof ProposalStatusSchema>;\n\n/**\n * Structured rejection feedback categories (Issue #1213).\n * Enables reject→refine→re-vote feedback loops by classifying rejection reasons.\n */\nexport const RejectionCategorySchema = z.enum([\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n]);\nexport type RejectionCategory = z.infer<typeof RejectionCategorySchema>;\n\n/**\n * All valid rejection category values, for runtime reference.\n */\nexport const REJECTION_CATEGORIES = RejectionCategorySchema.options;\n\n/**\n * Pre-verified finding emitted by a voter (#2245 v4 follow-up).\n * Mirrors `cli/voter-response.ts:RawFindingSchema` — kept inline here to\n * avoid a circular cli→consensus import. Downstream code in mcp/tools\n * adds the derived `verified` flag based on the gate fields.\n */\nconst FindingShapeSchema = z.object({\n summary: z.string().min(1).max(500),\n location: z.string().min(1).max(200),\n severity: z.enum(['critical', 'high', 'medium', 'low']).default('medium'),\n gate: z.object({\n reread_cited_line: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n traced_call_path: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n named_assertion: z.string().default(''),\n ruled_out_language_non_issue: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n }),\n claim: z.string().min(1).max(2000),\n});\n\n/**\n * A vote cast by an agent.\n */\nexport const VoteSchema = z.object({\n decision: VoteDecisionSchema,\n reasoning: z.string().min(1).describe('Explanation for the vote'),\n confidence: z.number().min(0).max(1).describe('Confidence level 0-1'),\n conditions: z.array(z.string()).optional().describe('Conditions for approval'),\n /** Structured rejection categories for reject→refine→re-vote loops (Issue #1213). */\n rejectionCategories: z\n .array(RejectionCategorySchema)\n .optional()\n .describe('Rejection reason categories when decision is reject'),\n /** Pre-verified PR-review findings (#2245 v4 follow-up). Optional;\n * populated only when the voter emits the structured top-level array. */\n findings: z.array(FindingShapeSchema).optional().describe('PR-review findings (pre-verified)'),\n timestamp: z.iso.datetime().optional(),\n});\nexport type Vote = z.infer<typeof VoteSchema>;\n\n/**\n * A proposal submitted for consensus.\n */\nexport const ProposalSchema = z.object({\n id: z.string().optional().describe('Auto-generated if not provided'),\n title: z.string().min(1).max(200).describe('Short proposal title'),\n description: z.string().min(1).describe('Detailed proposal description'),\n algorithm: ConsensusAlgorithmSchema,\n timeout: z.number().int().positive().optional().describe('Timeout in milliseconds'),\n requiredVoters: z.array(z.string()).optional().describe('Agent IDs that must vote'),\n metadata: z.record(z.string(), z.unknown()).optional().describe('Additional context'),\n createdAt: z.iso.datetime().optional(),\n});\nexport type Proposal = z.infer<typeof ProposalSchema>;\n\n/**\n * Unique identifier for a proposal.\n */\nexport type ProposalId = string;\n\n/**\n * Vote counts summary.\n */\nexport interface VoteCounts {\n approve: number;\n reject: number;\n abstain: number;\n total: number;\n}\n\n/**\n * Weighted vote counts for proof-of-learning.\n */\nexport interface WeightedVoteCounts {\n approve: number;\n reject: number;\n abstain: number;\n totalWeight: number;\n}\n\n/**\n * Result of a consensus decision.\n */\nexport interface ConsensusResult {\n proposalId: ProposalId;\n proposal: Proposal;\n outcome: ProposalStatus;\n votes: Map<string, Vote>;\n voteCounts: VoteCounts;\n weightedCounts?: WeightedVoteCounts | undefined;\n approvalPercentage: number;\n quorumReached: boolean;\n startedAt: string;\n closedAt: string;\n durationMs: number;\n}\n\n/**\n * Consensus result schema for validation.\n */\nexport const ConsensusResultSchema = z.object({\n proposalId: z.string(),\n proposal: ProposalSchema,\n outcome: ProposalStatusSchema,\n votes: z.map(z.string(), VoteSchema),\n voteCounts: z.object({\n approve: z.number().int().nonnegative(),\n reject: z.number().int().nonnegative(),\n abstain: z.number().int().nonnegative(),\n total: z.number().int().nonnegative(),\n }),\n weightedCounts: z\n .object({\n approve: z.number().nonnegative(),\n reject: z.number().nonnegative(),\n abstain: z.number().nonnegative(),\n totalWeight: z.number().nonnegative(),\n })\n .optional(),\n approvalPercentage: z.number().min(0).max(100),\n quorumReached: z.boolean(),\n startedAt: z.iso.datetime(),\n closedAt: z.iso.datetime(),\n durationMs: z.number().int().nonnegative(),\n});\n\n/**\n * Agent performance record for proof-of-learning.\n */\nexport interface AgentPerformance {\n agentId: string;\n totalVotes: number;\n correctVotes: number;\n successRate: number;\n lastUpdated: string;\n}\n\n/**\n * Agent performance schema.\n */\nexport const AgentPerformanceSchema = z.object({\n agentId: z.string(),\n totalVotes: z.number().int().nonnegative(),\n correctVotes: z.number().int().nonnegative(),\n successRate: z.number().min(0).max(1),\n lastUpdated: z.iso.datetime(),\n});\n\n/**\n * Proposal content caching configuration for determinism. (Issue #589)\n */\nexport interface ProposalCacheConfig {\n /** Enable content-based caching for repeated proposals */\n enabled: boolean;\n /** TTL in milliseconds (default: 1 hour) */\n ttlMs: number;\n /** Maximum cached entries (default: 500) */\n maxEntries: number;\n}\n\n/**\n * Incremental quorum configuration (Issue #1408).\n * When enabled, ambiguous votes trigger voter pool expansion.\n */\nexport interface IncrementalQuorumConfig {\n /** Enable incremental quorum expansion. Default: false */\n enabled: boolean;\n /** Maximum expansion rounds (5→7→9). Default: 2 */\n maxExpansionRounds: number;\n /** Voters to add per expansion round. Default: 2 */\n votersPerExpansion: number;\n /** Minimum average confidence to avoid expansion. Default: 0.6 */\n confidenceThreshold: number;\n /** Ambiguity band: if approval rate is within this of threshold, expand. Default: 0.15 */\n ambiguityBand: number;\n}\n\n/**\n * Default incremental quorum configuration.\n */\nexport const DEFAULT_INCREMENTAL_QUORUM_CONFIG: IncrementalQuorumConfig = {\n enabled: false,\n maxExpansionRounds: 2,\n votersPerExpansion: 2,\n confidenceThreshold: 0.6,\n ambiguityBand: 0.15,\n};\n\n/**\n * Callback to request additional voters for incremental quorum.\n * Returns the IDs of newly added voters.\n */\nexport type VoterExpansionCallback = (\n proposalId: ProposalId,\n currentVoterCount: number,\n requestedCount: number\n) => Promise<readonly string[]>;\n\n/**\n * Consensus engine configuration.\n */\nexport interface ConsensusEngineConfig {\n defaultTimeout: number;\n minVotersForQuorum: number;\n maxActiveProposals: number;\n enablePerformanceTracking: boolean;\n /** Maximum number of closed proposals to retain. Oldest are evicted when exceeded. (Issue #549) */\n maxClosedProposals: number;\n /** Content-based proposal caching for determinism (Issue #589) */\n proposalCache?: ProposalCacheConfig;\n /** Incremental quorum configuration (Issue #1408) */\n incrementalQuorum?: IncrementalQuorumConfig;\n}\n\n/**\n * Proposal cache configuration schema. (Issue #589)\n */\nexport const ProposalCacheConfigSchema = z.object({\n enabled: z.boolean().default(false),\n ttlMs: z.number().int().positive().default(3600000), // 1 hour\n maxEntries: z.number().int().positive().default(500),\n});\n\n/**\n * Consensus engine configuration schema.\n */\nexport const ConsensusEngineConfigSchema = z.object({\n defaultTimeout: z.number().int().positive().default(300000), // 5 minutes\n minVotersForQuorum: z.number().int().positive().default(2),\n maxActiveProposals: z.number().int().positive().default(100),\n enablePerformanceTracking: z.boolean().default(true),\n maxClosedProposals: z.number().int().positive().default(1000), // Issue #549\n proposalCache: ProposalCacheConfigSchema.optional(), // Issue #589\n});\n\n/**\n * Default configuration values.\n */\nexport const DEFAULT_CONSENSUS_CONFIG: ConsensusEngineConfig = {\n defaultTimeout: 300000, // 5 minutes\n minVotersForQuorum: 2,\n maxActiveProposals: 100,\n enablePerformanceTracking: true,\n maxClosedProposals: 1000, // Issue #549: Prevent unbounded memory growth\n};\n\n/**\n * The 2/3 supermajority agreement threshold — the governance constant for\n * \"supermajority\" / Byzantine (2-of-3) quorum. SINGLE SOURCE (#3571): every\n * consensus site that needs a supermajority references this instead of a bare\n * `0.67` literal, so the governance threshold cannot silently drift between\n * modules. (Per-algorithm values like 0.5/1.0 are intentionally NOT centralized\n * — 0.5 is semantically overloaded across several algorithms.)\n */\nexport const SUPERMAJORITY_THRESHOLD = 0.67;\n\n/**\n * Voting thresholds for each algorithm.\n */\nexport const VOTING_THRESHOLDS: Record<ConsensusAlgorithm, number> = {\n simple_majority: 0.5,\n supermajority: SUPERMAJORITY_THRESHOLD,\n unanimous: 1.0,\n proof_of_learning: 0.5, // Uses weighted voting\n opinion_wise: 0.5, // Uses correlation-aware Bayesian aggregation (Issue #333)\n higher_order: 0.5, // Alias for opinion_wise (Issue #514)\n};\n\n/**\n * Internal proposal state managed by the engine.\n */\nexport interface ProposalState {\n proposal: Proposal;\n status: ProposalStatus;\n votes: Map<string, Vote>;\n voteWeights: Map<string, number>;\n startedAt: Date;\n timeoutId?: ReturnType<typeof setTimeout>;\n /** Number of incremental quorum expansions applied (Issue #1408). */\n expansionRounds?: number;\n /**\n * True while a quorum expansion is awaiting its callback for this\n * proposal. Concurrent `vote()` calls check this to avoid double-\n * expanding across the `await` gap (Issue #2861). Per-proposal so\n * independent proposals never block each other.\n */\n expansionInFlight?: boolean;\n}\n\n/**\n * Consensus metrics for monitoring.\n */\nexport interface ConsensusMetrics {\n totalProposals: number;\n approvedProposals: number;\n rejectedProposals: number;\n timedOutProposals: number;\n averageDurationMs: number;\n averageVotesPerProposal: number;\n algorithmUsage: Record<ConsensusAlgorithm, number>;\n}\n\n/**\n * Consensus metrics schema.\n */\nexport const ConsensusMetricsSchema = z.object({\n totalProposals: z.number().int().nonnegative(),\n approvedProposals: z.number().int().nonnegative(),\n rejectedProposals: z.number().int().nonnegative(),\n timedOutProposals: z.number().int().nonnegative(),\n averageDurationMs: z.number().nonnegative(),\n averageVotesPerProposal: z.number().nonnegative(),\n algorithmUsage: z.record(ConsensusAlgorithmSchema, z.number().int().nonnegative()),\n});\n"],"mappings":"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","names":["z","READ_ONLY_TOOLS","AsyncLocalStorage","AsyncLocalStorage","err","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/mcp/middleware/validation.ts","../src/mcp/middleware/rate-limiter.ts","../src/mcp/middleware/policy-types.ts","../src/mcp/middleware/policy-helpers.ts","../src/mcp/middleware/policy-rules.ts","../src/mcp/middleware/policy.ts","../src/audit/secure-handler-audit.ts","../src/mcp/error-envelope.ts","../src/mcp/tools/tool-result.ts","../src/mcp/middleware/request-context.ts","../src/mcp/middleware/tool-input-sanitizer.ts","../src/mcp/middleware/secure-handler.ts","../src/mcp/mcp-notifier.ts","../src/mcp/middleware/tool-wrapper.ts","../src/mcp/middleware/timeout-guard.ts","../src/security/access-constraint-deriver/denylist.ts","../src/security/access-constraint-deriver/tool-risk.ts","../src/security/access-constraint-deriver/enforcer.ts","../src/security/access-constraint-deriver/mcp-guard.ts","../src/security/access-constraint-deriver/chain-adapter.ts","../src/mcp/middleware/middleware-chain.ts","../src/mcp/tools/tool-annotations.ts","../src/mcp/tool-annotations.ts","../src/consensus/types-core.ts"],"sourcesContent":["/**\n * nexus-agents/mcp - Validation Middleware\n *\n * Input validation helper using Zod schemas.\n * All tool inputs must be validated at the boundary.\n *\n * (Source: MCP Protocol 2025-11-25, Zod Documentation)\n */\n\nimport type { ZodType } from 'zod';\n\nimport { type Result, ok, err, ValidationError, formatZodError } from '../../core/index.js';\n\n// Re-export isZodError for backward compatibility\nexport { isZodError } from '../../core/index.js';\n\n/**\n * Validates tool input against a Zod schema.\n *\n * This function should be called at the start of every tool handler\n * to validate incoming arguments before processing.\n *\n * @template T - The expected type after validation\n * @param schema - The Zod schema to validate against\n * @param args - The unknown input to validate\n * @returns Result containing validated data or a ValidationError\n *\n * @example\n * ```typescript\n * const InputSchema = z.object({\n * task: z.string().min(1),\n * context: z.record(z.string(), z.unknown()).optional(),\n * });\n *\n * server.tool('my_tool', InputSchema.shape, async (args) => {\n * const result = validateToolInput(InputSchema, args);\n * if (!result.ok) {\n * return toolStructuredError({ errorCategory: 'validation', message: result.error.message });\n * }\n * const { task, context } = result.value;\n * // Process validated input...\n * });\n * ```\n */\nexport function validateToolInput<T>(\n schema: ZodType<T>,\n args: unknown\n): Result<T, ValidationError> {\n const parsed = schema.safeParse(args);\n\n if (parsed.success) {\n return ok(parsed.data);\n }\n\n const message = formatZodError(parsed.error);\n const validationError = new ValidationError(`Invalid tool input: ${message}`, {\n context: {\n issues: parsed.error.issues,\n receivedType: typeof args,\n },\n });\n\n return err(validationError);\n}\n\n/**\n * Creates a validation function bound to a specific schema.\n *\n * Useful for reusing the same schema across multiple tools.\n *\n * @template T - The expected type after validation\n * @param schema - The Zod schema to bind\n * @returns A validation function for the schema\n *\n * @example\n * ```typescript\n * const validateTask = createValidator(TaskSchema);\n *\n * // Later in tool handlers:\n * const result = validateTask(args);\n * ```\n */\nexport function createValidator<T>(\n schema: ZodType<T>\n): (args: unknown) => Result<T, ValidationError> {\n return (args: unknown) => validateToolInput(schema, args);\n}\n\n// `validateToolOutput` and `createOutputValidator` (Issue #547 sibling of\n// `validateToolInput` / `createValidator`) removed in #3022 — no MCP tool\n// ever called the output-validation path; every tool returns its result\n// without schema-validating first. If output validation comes back as a\n// real requirement, reintroduce alongside the per-tool wiring in the same\n// PR (activate-or-delete YAGNI — #2937, #2938, #2939, #2940, #3018, #3022).\n","/**\n * nexus-agents/mcp - Rate Limiter Middleware\n *\n * Token bucket implementation for rate limiting MCP tool calls.\n * Prevents abuse and ensures fair resource usage.\n *\n * (Source: Token Bucket Algorithm, RFC 6585)\n */\n\nimport { createLogger, type ILogger, getTimeProvider } from '../../core/index.js';\n\n/**\n * Configuration for the token bucket rate limiter.\n */\nexport interface RateLimiterConfig {\n /** Maximum number of tokens in the bucket */\n readonly capacity: number;\n /** Number of tokens added per interval */\n readonly refillRate: number;\n /** Interval in milliseconds between token refills (default: 1000ms) */\n readonly refillIntervalMs?: number;\n /** Optional logger instance */\n readonly logger?: ILogger;\n /** Optional identifier for logging */\n readonly name?: string;\n}\n\n/**\n * Current state of the rate limiter.\n */\nexport interface RateLimiterState {\n /** Current number of available tokens */\n readonly tokens: number;\n /** Capacity of the bucket */\n readonly capacity: number;\n /** Time until next token is available (0 if tokens available) */\n readonly nextTokenMs: number;\n}\n\n// Canonical source: config/timeouts.ts (Issue #1046)\nimport { CACHE_TIMEOUTS } from '../../config/timeouts.js';\n\nconst DEFAULT_REFILL_INTERVAL_MS = CACHE_TIMEOUTS.rateLimitRefillMs;\n\n/**\n * Token bucket rate limiter implementation.\n *\n * The token bucket algorithm allows for bursting up to the capacity,\n * while maintaining a steady-state rate equal to the refill rate.\n *\n * @example\n * ```typescript\n * const limiter = new RateLimiter({\n * capacity: 100,\n * refillRate: 10,\n * refillIntervalMs: 1000,\n * });\n *\n * if (limiter.tryAcquire()) {\n * // Proceed with operation\n * } else {\n * // Rate limited, reject or queue\n * }\n * ```\n */\nexport class RateLimiter {\n private tokens: number;\n private readonly capacity: number;\n private readonly refillRate: number;\n private readonly refillIntervalMs: number;\n private lastRefillTime: number;\n private readonly logger: ILogger;\n private readonly name: string;\n\n constructor(config: RateLimiterConfig) {\n this.capacity = config.capacity;\n this.refillRate = config.refillRate;\n this.refillIntervalMs = config.refillIntervalMs ?? DEFAULT_REFILL_INTERVAL_MS;\n this.tokens = this.capacity;\n this.lastRefillTime = getTimeProvider().now();\n this.name = config.name ?? 'rate-limiter';\n this.logger = config.logger ?? createLogger({ component: this.name });\n\n this.logger.debug('Rate limiter initialized', {\n capacity: this.capacity,\n refillRate: this.refillRate,\n refillIntervalMs: this.refillIntervalMs,\n });\n }\n\n /**\n * Refills tokens based on elapsed time.\n * Called automatically before each acquire attempt.\n */\n private refill(): void {\n const now = getTimeProvider().now();\n const elapsed = now - this.lastRefillTime;\n const intervals = Math.floor(elapsed / this.refillIntervalMs);\n\n if (intervals > 0) {\n const tokensToAdd = intervals * this.refillRate;\n this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);\n this.lastRefillTime = now - (elapsed % this.refillIntervalMs);\n\n if (tokensToAdd > 0) {\n this.logger.debug('Tokens refilled', {\n added: tokensToAdd,\n current: this.tokens,\n });\n }\n }\n }\n\n /**\n * Attempts to acquire a token.\n *\n * @param count - Number of tokens to acquire (default: 1)\n * @returns True if tokens were acquired, false if rate limited\n */\n tryAcquire(count = 1): boolean {\n this.refill();\n\n if (this.tokens >= count) {\n this.tokens -= count;\n this.logger.debug('Token acquired', {\n requested: count,\n remaining: this.tokens,\n });\n return true;\n }\n\n this.logger.warn('Rate limit exceeded', {\n requested: count,\n available: this.tokens,\n });\n return false;\n }\n\n /**\n * Gets the current state of the rate limiter.\n *\n * @returns The current rate limiter state\n */\n getState(): RateLimiterState {\n this.refill();\n\n const nextTokenMs =\n this.tokens > 0 ? 0 : this.refillIntervalMs - (getTimeProvider().now() - this.lastRefillTime);\n\n return {\n tokens: this.tokens,\n capacity: this.capacity,\n nextTokenMs: Math.max(0, nextTokenMs),\n };\n }\n\n /**\n * Resets the rate limiter to full capacity.\n * Useful for testing or after configuration changes.\n */\n reset(): void {\n this.tokens = this.capacity;\n this.lastRefillTime = getTimeProvider().now();\n this.logger.debug('Rate limiter reset', { tokens: this.tokens });\n }\n}\n\n/**\n * Creates a rate limiter with default settings suitable for MCP tools.\n *\n * Default configuration:\n * - Capacity: 100 tokens\n * - Refill rate: 10 tokens per second\n *\n * @param name - Optional name for the rate limiter\n * @param logger - Optional logger instance\n * @returns A configured RateLimiter instance\n */\nexport function createDefaultRateLimiter(name?: string, logger?: ILogger): RateLimiter {\n const config: RateLimiterConfig = {\n capacity: 100,\n refillRate: 10,\n refillIntervalMs: 1000,\n };\n if (name !== undefined) {\n (config as { name?: string }).name = name;\n }\n if (logger !== undefined) {\n (config as { logger?: ILogger }).logger = logger;\n }\n return new RateLimiter(config);\n}\n","/**\n * nexus-agents/mcp - Policy Firewall Types\n *\n * Type definitions for the authorization layer of MCP tool calls.\n *\n * (Source: OWASP ASVS 4.0, Authorization Controls)\n */\n\nimport { z } from 'zod';\n\nimport { SecurityError, type ILogger } from '../../core/index.js';\n\n// =============================================================================\n// Core Types\n// =============================================================================\n\n/**\n * Artifact type for policy context.\n * Artifacts are resources that can be referenced in policy decisions.\n */\nexport interface Artifact<T = unknown> {\n readonly id: string;\n readonly type: string;\n readonly value: T;\n readonly createdAt: Date;\n}\n\n/**\n * Execution mode for tool operations.\n * - 'read-only': Only read operations allowed (default)\n * - 'read-write': Both read and write operations allowed\n */\nexport type ExecutionMode = 'read-only' | 'read-write';\n\n/**\n * Policy enforcement mode.\n * - 'enforce': Block denied operations\n * - 'warn': Log denials but allow execution (for migration)\n */\nexport type PolicyMode = 'enforce' | 'warn';\n\n/**\n * Result of a policy evaluation.\n */\nexport interface PolicyDecision {\n readonly allowed: boolean;\n readonly reason: string;\n readonly requiredArtifact?: string;\n readonly ruleName?: string;\n}\n\n/**\n * Context provided to policy rules for evaluation.\n */\nexport interface PolicyContext {\n readonly toolName: string;\n readonly args: unknown;\n readonly mode: ExecutionMode;\n readonly artifacts?: Map<string, Artifact>;\n readonly workflowId?: string;\n readonly allowedPaths?: readonly string[];\n}\n\n/**\n * A single policy rule that can approve or deny operations.\n */\nexport interface PolicyRule {\n readonly name: string;\n readonly description: string;\n check(ctx: PolicyContext): PolicyDecision;\n}\n\n/**\n * Interface for the policy firewall.\n */\nexport interface IPolicyFirewall {\n evaluate(ctx: PolicyContext): PolicyDecision;\n addRule(rule: PolicyRule): void;\n removeRule(name: string): boolean;\n getRules(): readonly PolicyRule[];\n setMode(mode: PolicyMode): void;\n getMode(): PolicyMode;\n}\n\n/**\n * Configuration for the policy firewall.\n */\nexport interface PolicyFirewallConfig {\n /** Enforcement mode (default: 'enforce') */\n readonly mode?: PolicyMode;\n /** Logger instance */\n readonly logger?: ILogger;\n /** Initial rules to register */\n readonly rules?: readonly PolicyRule[];\n}\n\n// =============================================================================\n// Error Types\n// =============================================================================\n\n/**\n * Policy error for authorization failures.\n */\nexport class PolicyError extends SecurityError {\n readonly decision: PolicyDecision;\n\n constructor(message: string, decision: PolicyDecision) {\n super(message, {\n context: {\n allowed: decision.allowed,\n reason: decision.reason,\n ruleName: decision.ruleName,\n requiredArtifact: decision.requiredArtifact,\n },\n });\n this.name = 'PolicyError';\n this.decision = decision;\n }\n}\n\n// =============================================================================\n// Zod Schemas for Configuration\n// =============================================================================\n\n/**\n * Schema for policy configuration.\n */\nexport const PolicyConfigSchema = z.object({\n defaultMode: z.enum(['read-only', 'read-write']).default('read-only'),\n policyMode: z.enum(['enforce', 'warn']).default('enforce'),\n allowedPaths: z.array(z.string()).default(['./']),\n});\n\nexport type PolicyConfig = z.infer<typeof PolicyConfigSchema>;\n","/**\n * nexus-agents/mcp - Policy Firewall Helpers\n *\n * Utility functions for path validation and argument extraction.\n *\n * (Source: OWASP ASVS 4.0, Authorization Controls)\n */\n\n// =============================================================================\n// Path Utility Functions\n// =============================================================================\n\n/**\n * Validates a path against allowed roots.\n *\n * @param targetPath - The path to validate\n * @param allowedPaths - Array of allowed root paths\n * @returns True if the path is within an allowed root\n */\nexport function isPathSafe(targetPath: string, allowedPaths: readonly string[]): boolean {\n // Normalize the target path\n const normalizedTarget = normalizePath(targetPath);\n\n // Check if any allowed path is a prefix of the target\n for (const allowed of allowedPaths) {\n const normalizedAllowed = normalizePath(allowed);\n if (normalizedTarget.startsWith(normalizedAllowed)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Normalizes a path by removing trailing slashes and handling relative paths.\n */\nexport function normalizePath(p: string): string {\n // Remove trailing slashes\n let normalized = p.replace(/\\/{1,100}$/, '');\n\n // Handle relative paths\n if (normalized === '.') {\n normalized = '';\n } else if (normalized.startsWith('./')) {\n normalized = normalized.slice(2);\n }\n\n // Ensure absolute-like comparison\n if (!normalized.startsWith('/')) {\n normalized = '/' + normalized;\n }\n\n return normalized;\n}\n\n/**\n * Extracts path from tool arguments if present.\n */\nexport function extractPathFromArgs(args: unknown): string | undefined {\n if (args === null || typeof args !== 'object') {\n return undefined;\n }\n\n const argsObj = args as Record<string, unknown>;\n\n // Common path field names\n const pathFields = ['path', 'filePath', 'file_path', 'directory', 'dir', 'target'];\n\n for (const field of pathFields) {\n const value = argsObj[field];\n if (typeof value === 'string') {\n return value;\n }\n }\n\n return undefined;\n}\n","/**\n * nexus-agents/mcp - Policy Firewall Rules\n *\n * Default policy rules and constants for the authorization layer.\n *\n * (Source: OWASP ASVS 4.0, Authorization Controls)\n */\n\nimport type { PolicyContext, PolicyDecision, PolicyRule } from './policy-types.js';\nimport { isPathSafe, extractPathFromArgs } from './policy-helpers.js';\n\n// =============================================================================\n// Tool Classification Constants\n// =============================================================================\n\n/**\n * Tools that are considered write/mutation operations.\n */\nexport const MUTATION_TOOLS = new Set([\n 'write_file',\n 'edit_file',\n 'delete_file',\n 'create_directory',\n 'remove_directory',\n 'execute_command',\n 'run_shell',\n 'bash',\n 'create_expert',\n 'run_workflow',\n]);\n\n/**\n * Tools that are considered read-only operations.\n */\nexport const READ_ONLY_TOOLS = new Set([\n 'read_file',\n 'list_directory',\n 'search_files',\n 'get_status',\n 'orchestrate',\n 'delegate_to_model',\n]);\n\n// =============================================================================\n// Tool Classification Functions\n// =============================================================================\n\n/**\n * Checks if a tool is a mutation operation.\n */\nexport function isMutationTool(toolName: string): boolean {\n // Check explicit mutation tools\n if (MUTATION_TOOLS.has(toolName)) {\n return true;\n }\n\n // Check explicit read-only tools\n if (READ_ONLY_TOOLS.has(toolName)) {\n return false;\n }\n\n // Default to treating unknown tools as mutations (safe default)\n return true;\n}\n\n// =============================================================================\n// Default Policy Rules\n// =============================================================================\n\n/**\n * Policy rule that denies mutation operations when mode is 'read-only'.\n *\n * This ensures that write operations are only allowed when explicitly\n * enabled via the 'read-write' mode.\n */\nexport const denyMutationsWithoutModeRule: PolicyRule = {\n name: 'deny-mutations-without-mode',\n description: 'Blocks write operations unless mode is read-write',\n check(ctx: PolicyContext): PolicyDecision {\n // If mode is read-write, allow all operations\n if (ctx.mode === 'read-write') {\n return { allowed: true, reason: 'Read-write mode enabled' };\n }\n\n // Check if this is a mutation tool\n if (isMutationTool(ctx.toolName)) {\n return {\n allowed: false,\n reason: `Tool '${ctx.toolName}' is a mutation operation but mode is '${ctx.mode}'. Set mode to 'read-write' to enable.`,\n };\n }\n\n // Read-only tool in read-only mode is allowed\n return { allowed: true, reason: 'Read-only operation allowed' };\n },\n};\n\n/**\n * Policy rule that validates paths against allowed roots.\n *\n * Prevents path traversal attacks by ensuring all file operations\n * target paths within configured allowed directories.\n */\nexport const safePathsRule: PolicyRule = {\n name: 'safe-paths',\n description: 'Validates paths against allowed root directories',\n check(ctx: PolicyContext): PolicyDecision {\n // Extract path from arguments\n const targetPath = extractPathFromArgs(ctx.args);\n\n // If no path in args, allow (not a file operation)\n if (targetPath === undefined) {\n return { allowed: true, reason: 'No path argument found' };\n }\n\n // Check for obvious path traversal attempts\n if (targetPath.includes('..')) {\n return {\n allowed: false,\n reason: `Path contains '..' which may indicate path traversal: ${targetPath}`,\n };\n }\n\n // Get allowed paths from context or use default\n const allowedPaths = ctx.allowedPaths ?? ['./'];\n\n // Validate path is within allowed roots\n if (!isPathSafe(targetPath, allowedPaths)) {\n return {\n allowed: false,\n reason: `Path '${targetPath}' is outside allowed directories: ${allowedPaths.join(', ')}`,\n };\n }\n\n return { allowed: true, reason: 'Path is within allowed directories' };\n },\n};\n","/**\n * nexus-agents/mcp - Policy Firewall Middleware\n *\n * Authorization layer for MCP tool calls. Evaluates policy rules\n * to determine whether operations should be allowed or denied.\n *\n * This is separate from validation - validation checks if input is well-formed,\n * policy checks if the operation is authorized.\n *\n * (Source: OWASP ASVS 4.0, Authorization Controls)\n */\n\nimport { createLogger, type ILogger, type Result, ok, err } from '../../core/index.js';\n\nimport type {\n Artifact,\n ExecutionMode,\n PolicyMode,\n PolicyDecision,\n PolicyContext,\n PolicyRule,\n IPolicyFirewall,\n PolicyFirewallConfig,\n} from './policy-types.js';\nimport { PolicyError } from './policy-types.js';\nimport { denyMutationsWithoutModeRule, safePathsRule } from './policy-rules.js';\n\n// =============================================================================\n// PolicyFirewall Implementation\n// =============================================================================\n\n/**\n * Policy firewall that evaluates rules to authorize or deny operations.\n *\n * Rules are evaluated in order. The first rule that denies the operation\n * stops evaluation and returns the denial. If all rules pass, the operation\n * is allowed.\n *\n * @example\n * ```typescript\n * const firewall = new PolicyFirewall({ mode: 'enforce' });\n *\n * // Add rules\n * firewall.addRule(denyMutationsWithoutModeRule);\n * firewall.addRule(safePathsRule);\n *\n * // Evaluate\n * const decision = firewall.evaluate({\n * toolName: 'write_file',\n * args: { path: '/etc/passwd' },\n * mode: 'read-only',\n * });\n *\n * if (!decision.allowed) {\n * console.error(`Denied: ${decision.reason}`);\n * }\n * ```\n */\nexport class PolicyFirewall implements IPolicyFirewall {\n private readonly rules: PolicyRule[] = [];\n private mode: PolicyMode;\n private readonly logger: ILogger;\n\n constructor(config?: PolicyFirewallConfig) {\n this.mode = config?.mode ?? 'enforce';\n this.logger = config?.logger ?? createLogger({ component: 'policy-firewall' });\n\n // Register initial rules if provided\n if (config?.rules) {\n for (const rule of config.rules) {\n this.rules.push(rule);\n }\n }\n\n this.logger.debug('Policy firewall initialized', {\n mode: this.mode,\n ruleCount: this.rules.length,\n });\n }\n\n /**\n * Evaluates all policy rules against the given context.\n *\n * Rules are evaluated in order. The first rule that denies stops\n * evaluation and returns the denial decision.\n *\n * @param ctx - The policy context to evaluate\n * @returns The policy decision\n */\n evaluate(ctx: PolicyContext): PolicyDecision {\n this.logger.debug('Evaluating policy', {\n toolName: ctx.toolName,\n mode: ctx.mode,\n ruleCount: this.rules.length,\n });\n\n // If no rules, allow by default\n if (this.rules.length === 0) {\n return this.allowWithReason(ctx, 'No policy rules configured');\n }\n\n // Evaluate each rule in order\n for (const rule of this.rules) {\n const decision = rule.check(ctx);\n\n if (!decision.allowed) {\n return this.handleDenial(ctx, rule, decision);\n }\n }\n\n // All rules passed\n return this.allowWithReason(ctx, 'All policy rules passed');\n }\n\n /**\n * Creates an allow decision with the given reason and logs it.\n */\n private allowWithReason(ctx: PolicyContext, reason: string): PolicyDecision {\n const decision: PolicyDecision = { allowed: true, reason };\n this.logDecision(ctx, decision);\n return decision;\n }\n\n /**\n * Handles a rule denial, respecting warn mode if configured.\n */\n private handleDenial(\n ctx: PolicyContext,\n rule: PolicyRule,\n decision: PolicyDecision\n ): PolicyDecision {\n const denialDecision: PolicyDecision = {\n ...decision,\n ruleName: rule.name,\n };\n\n this.logDecision(ctx, denialDecision);\n\n // In warn mode, log but still allow\n if (this.mode === 'warn') {\n this.logger.warn('Policy denial overridden by warn mode', {\n toolName: ctx.toolName,\n ruleName: rule.name,\n reason: decision.reason,\n });\n return {\n allowed: true,\n reason: `[WARN MODE] Would be denied: ${decision.reason}`,\n ruleName: rule.name,\n };\n }\n\n return denialDecision;\n }\n\n /**\n * Adds a policy rule to the firewall.\n *\n * @param rule - The rule to add\n */\n addRule(rule: PolicyRule): void {\n // Prevent duplicate rules\n const existingIndex = this.rules.findIndex((r) => r.name === rule.name);\n if (existingIndex >= 0) {\n this.logger.warn('Replacing existing policy rule', { ruleName: rule.name });\n this.rules[existingIndex] = rule;\n } else {\n this.rules.push(rule);\n this.logger.debug('Policy rule added', { ruleName: rule.name });\n }\n }\n\n /**\n * Removes a policy rule by name.\n *\n * @param name - The name of the rule to remove\n * @returns True if the rule was found and removed\n */\n removeRule(name: string): boolean {\n const index = this.rules.findIndex((r) => r.name === name);\n if (index >= 0) {\n this.rules.splice(index, 1);\n this.logger.debug('Policy rule removed', { ruleName: name });\n return true;\n }\n return false;\n }\n\n /**\n * Gets all registered policy rules.\n *\n * @returns A readonly array of policy rules\n */\n getRules(): readonly PolicyRule[] {\n return [...this.rules];\n }\n\n /**\n * Sets the policy enforcement mode.\n *\n * @param mode - The new enforcement mode\n */\n setMode(mode: PolicyMode): void {\n const previousMode = this.mode;\n this.mode = mode;\n this.logger.info('Policy mode changed', { from: previousMode, to: mode });\n }\n\n /**\n * Gets the current policy enforcement mode.\n *\n * @returns The current mode\n */\n getMode(): PolicyMode {\n return this.mode;\n }\n\n /**\n * Logs a policy decision for audit purposes.\n */\n private logDecision(ctx: PolicyContext, decision: PolicyDecision): void {\n const logData = {\n toolName: ctx.toolName,\n mode: ctx.mode,\n workflowId: ctx.workflowId,\n allowed: decision.allowed,\n reason: decision.reason,\n ruleName: decision.ruleName,\n };\n\n if (decision.allowed) {\n this.logger.debug('Policy decision: ALLOWED', logData);\n } else {\n this.logger.warn('Policy decision: DENIED', logData);\n }\n }\n}\n\n// =============================================================================\n// Factory Functions\n// =============================================================================\n\n/**\n * Creates a policy firewall with default rules.\n *\n * Default rules included:\n * - deny-mutations-without-mode\n * - safe-paths\n *\n * @param config - Optional configuration\n * @returns A configured PolicyFirewall instance\n */\nexport function createDefaultPolicyFirewall(config?: PolicyFirewallConfig): PolicyFirewall {\n const firewall = new PolicyFirewall(config);\n\n // Add default rules\n firewall.addRule(denyMutationsWithoutModeRule);\n firewall.addRule(safePathsRule);\n\n return firewall;\n}\n\n/**\n * Evaluates a policy context and returns a Result.\n *\n * This is a convenience function that wraps the firewall evaluation\n * in a Result type for easier error handling.\n *\n * @param firewall - The policy firewall to use\n * @param ctx - The policy context to evaluate\n * @returns Result containing void on success or PolicyError on denial\n */\nexport function evaluatePolicy(\n firewall: IPolicyFirewall,\n ctx: PolicyContext\n): Result<void, PolicyError> {\n const decision = firewall.evaluate(ctx);\n\n if (decision.allowed) {\n return ok(undefined);\n }\n\n return err(new PolicyError(`Policy denied: ${decision.reason}`, decision));\n}\n\n/**\n * Creates a policy context from tool invocation parameters.\n *\n * @param toolName - Name of the tool being invoked\n * @param args - Tool arguments\n * @param options - Additional context options\n * @returns A PolicyContext object\n */\nexport function createPolicyContext(\n toolName: string,\n args: unknown,\n options?: {\n mode?: ExecutionMode;\n artifacts?: Map<string, Artifact>;\n workflowId?: string;\n allowedPaths?: readonly string[];\n }\n): PolicyContext {\n // Build base context with required properties\n const base = {\n toolName,\n args,\n mode: options?.mode ?? 'read-only',\n };\n\n // Use Object.assign to build result, only adding optional properties\n // when they are actually defined (to satisfy exactOptionalPropertyTypes)\n const result: Record<string, unknown> = { ...base };\n\n if (options?.artifacts !== undefined) {\n result['artifacts'] = options.artifacts;\n }\n if (options?.workflowId !== undefined) {\n result['workflowId'] = options.workflowId;\n }\n if (options?.allowedPaths !== undefined) {\n result['allowedPaths'] = options.allowedPaths;\n }\n\n return result as unknown as PolicyContext;\n}\n\n// =============================================================================\n// Re-exports for backward compatibility\n// =============================================================================\n\nexport * from './policy-types.js';\nexport * from './policy-rules.js';\nexport * from './policy-helpers.js';\n","/**\n * nexus-agents/audit - SecureHandler Audit Integration\n *\n * Integration helper to add audit logging to SecureHandler middleware.\n *\n * (Source: Issue #193 - Phase 3 structured audit logging)\n *\n * @module audit/secure-handler-audit\n */\n\nimport type { IAuditLogger, AuditActor, AuditOutcome } from './audit-types.js';\nimport type { RequestContext } from '../mcp/middleware/request-context.js';\n\n/**\n * Configuration for audit-enabled secure handler.\n */\nexport interface AuditHandlerConfig {\n /** Audit logger instance */\n auditLogger: IAuditLogger;\n /** Default actor for requests without caller info */\n defaultActor?: AuditActor | undefined;\n}\n\n/**\n * Creates an AuditActor from RequestContext.\n */\nexport function actorFromContext(ctx: RequestContext, fallback?: AuditActor): AuditActor {\n const caller = ctx.caller;\n const clientId = caller.clientId;\n if (clientId !== undefined && clientId.length > 0) {\n return {\n type: clientId.includes('api') ? 'external' : clientId.includes('cli') ? 'agent' : 'user',\n id: clientId,\n name: caller.userAgent,\n };\n }\n return fallback ?? { type: 'system', id: 'unknown', name: 'Unknown Caller' };\n}\n\n/**\n * Maps tool result to audit outcome.\n */\nexport function resultToOutcome(\n isError: boolean | undefined,\n isPolicyDenied: boolean\n): AuditOutcome {\n if (isPolicyDenied) return 'denied';\n if (isError === true) return 'failure';\n return 'success';\n}\n\n/** Options for logging tool invocation audit */\nexport interface LogToolInvocationOpts {\n auditLogger: IAuditLogger;\n toolName: string;\n outcome: AuditOutcome;\n actor: AuditActor;\n requestId: string;\n durationMs?: number | undefined;\n errorMessage?: string | undefined;\n}\n\n/**\n * Logs tool invocation to audit logger.\n */\nexport function logToolInvocationAudit(opts: LogToolInvocationOpts): void {\n opts.auditLogger.logToolInvocation({\n toolName: opts.toolName,\n outcome: opts.outcome,\n actor: opts.actor,\n requestId: opts.requestId,\n durationMs: opts.durationMs,\n errorMessage: opts.errorMessage,\n });\n}\n\n/** Options for logging policy audit */\nexport interface LogPolicyAuditOpts {\n auditLogger: IAuditLogger;\n policyName: string;\n decision: 'allow' | 'deny';\n reason: string;\n toolName: string;\n actor: AuditActor;\n requestId: string;\n}\n\n/**\n * Logs policy decision to audit logger.\n */\nexport function logPolicyAudit(opts: LogPolicyAuditOpts): void {\n opts.auditLogger.logPolicyDecision({\n policyName: opts.policyName,\n decision: opts.decision,\n reason: opts.reason,\n toolName: opts.toolName,\n actor: opts.actor,\n requestId: opts.requestId,\n });\n}\n\n/** Options for logging rate limit audit */\nexport interface LogRateLimitAuditOpts {\n auditLogger: IAuditLogger;\n toolName: string;\n actor: AuditActor;\n currentRate: number;\n limitRate: number;\n requestId: string;\n}\n\n/**\n * Logs rate limit violation to audit logger.\n */\nexport function logRateLimitAudit(opts: LogRateLimitAuditOpts): void {\n opts.auditLogger.logRateLimitViolation({\n toolName: opts.toolName,\n actor: opts.actor,\n currentRate: opts.currentRate,\n limitRate: opts.limitRate,\n requestId: opts.requestId,\n });\n}\n","/**\n * nexus-agents/mcp - Structured Tool Error Envelope\n *\n * Caller-facing error contract for MCP tools. Replaces the opaque\n * `{ isError: true, content: [{ text }] }` string shape with a structured\n * envelope so callers (other tools, voter panels, the Claude/Codex/Gemini/\n * OpenCode harnesses) can reason about retry-safety and recovery path\n * instead of string-matching arbitrary text.\n *\n * SCOPE — this envelope is caller-facing ONLY. The routing/circuit-breaker\n * layer classifies adapter subprocess failures through its own\n * `categorizeOutcomeError()` path (orchestration/outcomes/outcome-types.ts)\n * and never reads this envelope. `coarsenFailureCategory()` is a one-way\n * convenience for the rare tool that internally catches an\n * `OutcomeFailureCategory`-classified error and wants to surface it to its\n * caller — it is not, and must not become, a routing input. The two\n * taxonomies serve different layers; this is the single authoritative\n * projection between them.\n *\n * @module mcp/error-envelope\n * @see Issue #2649\n */\n\nimport { z } from 'zod';\nimport type { OutcomeFailureCategory } from '../orchestration/outcomes/outcome-types.js';\n\n// ============================================================================\n// Schema\n// ============================================================================\n\n/**\n * Caller-facing error category. Deliberately coarser than the routing\n * layer's 11-value `OutcomeFailureCategory` — a tool's caller only needs\n * enough resolution to choose a recovery path:\n *\n * - `transient` — network blip, rate limit, timeout. Retry is safe.\n * - `validation` — input shape/values wrong. Caller must fix its args.\n * - `permission` — auth / authorization / sandbox / access-policy denial.\n * - `business` — domain-logic refusal (dedup hit, precondition not met).\n * An expected, non-bug outcome — not a failure to retry.\n * - `internal` — unexpected, bug-class. Not retry-class; escalate.\n */\nexport const ErrorCategorySchema = z.enum([\n 'transient',\n 'validation',\n 'permission',\n 'business',\n 'internal',\n]);\n\nexport type ErrorCategory = z.infer<typeof ErrorCategorySchema>;\n\n/**\n * Structured error envelope returned by MCP tools. Carried in the tool\n * result's `structuredContent` under the `error` key; the human-readable\n * `message` is also mirrored into `content[].text` for display.\n */\nexport const ToolErrorEnvelopeSchema = z.object({\n errorCategory: ErrorCategorySchema,\n /** Whether retrying the same call could succeed without caller changes. */\n isRetryable: z.boolean(),\n /** Human-readable summary. Bounded to keep stack traces out of results. */\n message: z.string().min(1).max(2000),\n /**\n * Optional structured context. MUST NOT carry secrets, credentials,\n * absolute filesystem paths, or raw Error/response objects — those are\n * an information-disclosure risk (this field is not output-sanitized).\n */\n detail: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type ToolErrorEnvelope = z.infer<typeof ToolErrorEnvelopeSchema>;\n\n/**\n * `_meta` key the envelope is carried under on a tool result. It lives in\n * `_meta` — NOT `structuredContent` — because the MCP client validates\n * `structuredContent` against the tool's `outputSchema` even on error\n * results (SDK `client/index.js`: it only guards on presence, not on\n * `isError`), so an envelope in `structuredContent` breaks every tool\n * that has an `outputSchema`. `_meta` is the spec's out-of-band metadata\n * channel and is never schema-validated. Namespaced to avoid collisions.\n */\nexport const ERROR_ENVELOPE_META_KEY = 'nexus-agents/error';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Default retry-safety for a category. Only `transient` errors are\n * retry-safe by default; callers can override per-call when a specific\n * `internal` or `business` error is known to be retryable.\n */\nexport function defaultRetryable(category: ErrorCategory): boolean {\n return category === 'transient';\n}\n\n/**\n * The single authoritative projection from the routing layer's 11-value\n * `OutcomeFailureCategory` down to the 5-value caller-facing\n * `ErrorCategory`. A `Record` over every key — adding a 12th\n * `OutcomeFailureCategory` value without extending this map is a compile\n * error, which is the drift safeguard.\n *\n * One-way only: there is no `un-coarsen`, by design — the routing layer\n * keeps its own granular classification and never round-trips through here.\n */\nconst FAILURE_CATEGORY_COARSENING: Record<OutcomeFailureCategory, ErrorCategory> = {\n timeout: 'transient',\n rate_limit: 'transient',\n connection: 'transient',\n authentication: 'permission',\n validation: 'validation',\n parse: 'validation',\n crash: 'internal',\n adapter_unavailable: 'internal',\n execution: 'internal',\n generic: 'internal',\n unknown: 'internal',\n};\n\n/**\n * Coarsen a routing-layer `OutcomeFailureCategory` to a caller-facing\n * `ErrorCategory`. Use this only when a tool has caught an error already\n * classified by the routing layer and wants to surface it in its envelope.\n */\nexport function coarsenFailureCategory(category: OutcomeFailureCategory): ErrorCategory {\n return FAILURE_CATEGORY_COARSENING[category];\n}\n\n/**\n * Extract and validate a `ToolErrorEnvelope` from a tool result's `_meta`\n * object. Returns `null` when `_meta` is absent or does not carry a\n * parseable envelope under {@link ERROR_ENVELOPE_META_KEY}. Used by\n * envelope-aware callers.\n */\nexport function parseToolErrorEnvelope(meta: unknown): ToolErrorEnvelope | null {\n if (meta === null || typeof meta !== 'object') {\n return null;\n }\n const candidate = (meta as Record<string, unknown>)[ERROR_ENVELOPE_META_KEY];\n const result = ToolErrorEnvelopeSchema.safeParse(candidate);\n return result.success ? result.data : null;\n}\n","/**\n * nexus-agents/mcp - Tool Result Helpers\n *\n * Canonical type and factory functions for MCP tool results.\n * Extracted from index.ts to allow tool implementations to import\n * without circular dependencies.\n *\n * @module mcp/tools/tool-result\n */\n\nimport type { ILogger } from '../../core/index.js';\nimport type { RateLimiter } from '../middleware/rate-limiter.js';\nimport type { SecurityConfig } from '../../config/schemas.js';\nimport {\n defaultRetryable,\n ERROR_ENVELOPE_META_KEY,\n type ErrorCategory,\n type ToolErrorEnvelope,\n} from '../error-envelope.js';\n\n// ============================================================================\n// Base Dependencies\n// ============================================================================\n\n/**\n * Common dependency interface shared by all MCP tool handlers.\n *\n * Tool-specific deps interfaces should extend this base.\n * (Source: Issue #1439 — DRY extraction of 25 duplicated Deps interfaces)\n */\nexport interface BaseMcpToolDeps {\n /** Optional logger */\n logger?: ILogger;\n /** Rate limiter for throttling tool calls (required) */\n rateLimiter: RateLimiter;\n /** Security configuration (includes timeout settings) */\n security?: SecurityConfig | undefined;\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * MCP tool content types.\n */\nexport interface TextContent {\n type: 'text';\n text: string;\n}\n\n/**\n * MCP tool result.\n *\n * Uses mutable properties for compatibility with secure-handler\n * sanitization (which rewrites `text` in-place).\n */\nexport interface ToolResult {\n content: Array<TextContent>;\n isError?: boolean;\n /** Structured output for SDK outputSchema validation (Issue #1117) */\n structuredContent?: Record<string, unknown>;\n /**\n * Out-of-band metadata, never validated against `outputSchema`. The\n * structured error envelope (#2649) is carried here under\n * `ERROR_ENVELOPE_META_KEY`.\n */\n _meta?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Creates a successful tool result.\n *\n * @param text - The result text\n * @returns A ToolResult with the text content\n *\n * @example\n * ```typescript\n * return toolSuccess(JSON.stringify({ status: 'ok', data: result }));\n * ```\n */\nexport function toolSuccess(text: string): ToolResult {\n return {\n content: [{ type: 'text', text }],\n };\n}\n\n/**\n * Creates a successful tool result with structured content for outputSchema validation.\n *\n * When a tool is registered with outputSchema, the SDK validates structuredContent\n * against the schema. This helper returns both text (for display) and structured data.\n *\n * @param data - The structured result data (must match the tool's outputSchema)\n * @returns A ToolResult with both text content and structuredContent\n *\n * @example\n * ```typescript\n * return toolSuccessStructured({ experts: [...], count: 10 });\n * ```\n */\nexport function toolSuccessStructured(data: Record<string, unknown>): ToolResult {\n return {\n content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],\n structuredContent: data,\n };\n}\n\n/**\n * Input for {@link toolStructuredError}. `isRetryable` is optional — when\n * omitted it is derived from the category via `defaultRetryable()`.\n */\nexport interface ToolStructuredErrorInput {\n errorCategory: ErrorCategory;\n message: string;\n isRetryable?: boolean;\n detail?: Record<string, unknown>;\n}\n\n/**\n * Creates a structured error tool result (#2649). The envelope is carried\n * in `_meta` (under `ERROR_ENVELOPE_META_KEY`) — NOT `structuredContent`,\n * which the MCP client validates against the tool's `outputSchema` even\n * on error results. `message` is mirrored into `content[].text` for\n * display.\n *\n * @example\n * ```typescript\n * if (!validated.success) {\n * return toolStructuredError({\n * errorCategory: 'validation',\n * message: `Validation error: ${formatZodError(validated.error)}`,\n * });\n * }\n * ```\n */\nexport function toolStructuredError(input: ToolStructuredErrorInput): ToolResult {\n const envelope: ToolErrorEnvelope = {\n errorCategory: input.errorCategory,\n isRetryable: input.isRetryable ?? defaultRetryable(input.errorCategory),\n message: input.message,\n ...(input.detail !== undefined ? { detail: input.detail } : {}),\n };\n return {\n isError: true,\n content: [{ type: 'text', text: envelope.message }],\n _meta: { [ERROR_ENVELOPE_META_KEY]: envelope },\n };\n}\n\n/**\n * Creates an error tool result.\n *\n * Back-compat alias for {@link toolStructuredError} — maps to the\n * conservative `internal` / non-retryable envelope. New code should call\n * `toolStructuredError` directly with the correct category; this alias\n * exists so the ~64 legacy call sites keep working during the #2649\n * migration sweep.\n *\n * @param message - The error message\n * @returns A ToolResult with isError set to true and an `internal` envelope\n */\nexport function toolError(message: string): ToolResult {\n return toolStructuredError({ errorCategory: 'internal', message });\n}\n","/**\n * nexus-agents/mcp - Request Context Middleware\n *\n * Provides request ID generation and caller context tracking for MCP tools.\n * (Source: Issue #185 Phase 1 - Request context & PolicyFirewall integration)\n *\n * @module mcp/middleware/request-context\n */\n\nimport { randomBytes } from 'node:crypto';\nimport { getTimeProvider } from '../../core/index.js';\nimport type { TrustTier } from '../../security/trust-types.js';\n\n/**\n * Authenticated user information.\n * (Source: Issue #739 - MCP authentication)\n */\nexport interface AuthenticatedUser {\n /** Unique user/client identifier */\n readonly id: string;\n /** Human-readable name (optional) */\n readonly name?: string;\n /** Granted permissions/scopes (optional) */\n readonly permissions?: readonly string[];\n}\n\n/**\n * Caller identification for audit trails.\n */\nexport interface CallerInfo {\n /** Client identifier (e.g., 'claude-cli', 'gemini-cli') */\n readonly clientId?: string;\n /** User agent string if available */\n readonly userAgent?: string;\n /** Session ID for request correlation */\n readonly sessionId?: string;\n /** IP address or transport identifier */\n readonly transport?: string;\n /** Whether the request is authenticated (Issue #739) */\n readonly authenticated?: boolean;\n /** Authenticated user information (Issue #739) */\n readonly authenticatedUser?: AuthenticatedUser;\n}\n\n/**\n * Request context for MCP tool invocations.\n * Immutable once created.\n */\nexport interface RequestContext {\n /** Unique request identifier (format: req_<16 hex chars>) */\n readonly requestId: string;\n /** Timestamp when request was received (ISO 8601, ET) */\n readonly timestamp: string;\n /** Tool being invoked */\n readonly toolName: string;\n /** Caller information for audit */\n readonly caller: CallerInfo;\n /**\n * Trust tier for this request (Issue #828).\n * Derived from caller authentication state:\n * - '1' = Authenticated + known client, or stdio (local-only)\n * - '2' = Authenticated via network\n * - '3' = Unauthenticated network request\n * - '4' = Request with detected injection patterns (set by sanitizer)\n */\n readonly trustTier: TrustTier;\n /** Trace ID for distributed tracing correlation */\n readonly traceId?: string;\n /** Parent span ID if part of a larger trace */\n readonly parentSpanId?: string;\n}\n\n/**\n * Options for creating a request context.\n */\nexport interface CreateContextOptions {\n /** Tool name being invoked */\n toolName: string;\n /** Optional caller information */\n caller?: CallerInfo;\n /** Optional explicit trust tier override (defaults to derived from caller) */\n trustTier?: TrustTier;\n /** Optional trace ID for correlation */\n traceId?: string;\n /** Optional parent span ID */\n parentSpanId?: string;\n}\n\n/**\n * Generates a cryptographically secure request ID.\n * Format: req_<16 hex characters>\n *\n * @returns Unique request identifier\n */\nexport function generateRequestId(): string {\n const bytes = randomBytes(8);\n return `req_${bytes.toString('hex')}`;\n}\n\n/**\n * Generates a session ID for request correlation.\n * Format: sess_<12 hex characters>\n *\n * @returns Unique session identifier\n */\nexport function generateSessionId(): string {\n const bytes = randomBytes(6);\n return `sess_${bytes.toString('hex')}`;\n}\n\n/**\n * Formats timestamp in ISO 8601 format with ET timezone.\n * (Source: CLAUDE.md - Time Authority section)\n */\nfunction formatTimestamp(): string {\n const now = new Date(getTimeProvider().now());\n const formatter = new Intl.DateTimeFormat('en-US', {\n timeZone: 'America/New_York',\n timeZoneName: 'shortOffset',\n });\n const parts = formatter.formatToParts(now);\n const offset = parts.find((p) => p.type === 'timeZoneName')?.value ?? '-05:00';\n const base = now.toLocaleString('sv-SE', {\n timeZone: 'America/New_York',\n hour12: false,\n });\n return base.replace(' ', 'T') + offset.replace('GMT', '');\n}\n\n/**\n * Derives trust tier from caller authentication state (Issue #828).\n *\n * - Authenticated + known CLI client (claude, gemini, codex) → Tier 1\n * - stdio transport (local-only, no network) → Tier 1\n * - Authenticated via network → Tier 2\n * - Unauthenticated → Tier 3\n */\nexport function deriveTrustTier(caller: CallerInfo): TrustTier {\n const knownClients = ['claude-cli', 'gemini-cli', 'codex-cli'];\n\n if (caller.transport === 'stdio') return '1';\n\n if (caller.authenticated === true) {\n if (caller.clientId !== undefined && knownClients.includes(caller.clientId)) {\n return '1';\n }\n return '2';\n }\n\n return '3';\n}\n\n/**\n * Creates an immutable request context for an MCP tool invocation.\n *\n * @param options - Context creation options\n * @returns Immutable request context\n */\nexport function createRequestContext(options: CreateContextOptions): RequestContext {\n const caller = options.caller ?? {};\n const context: RequestContext = {\n requestId: generateRequestId(),\n timestamp: formatTimestamp(),\n toolName: options.toolName,\n caller,\n trustTier: options.trustTier ?? deriveTrustTier(caller),\n ...(options.traceId !== undefined && { traceId: options.traceId }),\n ...(options.parentSpanId !== undefined && { parentSpanId: options.parentSpanId }),\n };\n\n // Freeze to ensure immutability\n return Object.freeze(context);\n}\n\n/**\n * Extracts caller info from MCP transport metadata.\n * Currently supports extracting from request headers or environment.\n *\n * @param metadata - Optional transport metadata\n * @returns Caller information\n */\nexport function extractCallerInfo(metadata?: Record<string, unknown>): CallerInfo {\n const caller: CallerInfo = {};\n\n if (metadata !== undefined) {\n // Extract all available fields from metadata\n const extracted: CallerInfo = {\n ...caller,\n ...(typeof metadata['clientId'] === 'string' ? { clientId: metadata['clientId'] } : {}),\n ...(typeof metadata['userAgent'] === 'string' ? { userAgent: metadata['userAgent'] } : {}),\n ...(typeof metadata['sessionId'] === 'string' ? { sessionId: metadata['sessionId'] } : {}),\n };\n\n // If any metadata was extracted, return it directly\n if (\n typeof metadata['clientId'] === 'string' ||\n typeof metadata['userAgent'] === 'string' ||\n typeof metadata['sessionId'] === 'string'\n ) {\n return extracted;\n }\n }\n\n // Fallback to environment variables for known CLI tools\n const claudeSession = process.env['CLAUDE_SESSION_ID'];\n if (claudeSession !== undefined) {\n return { ...caller, clientId: 'claude-cli', sessionId: claudeSession };\n }\n\n const geminiSession = process.env['GEMINI_SESSION_ID'];\n if (geminiSession !== undefined) {\n return { ...caller, clientId: 'gemini-cli', sessionId: geminiSession };\n }\n\n return caller;\n}\n\n/**\n * Formats request context for logging.\n * Extracts essential fields for log context.\n *\n * @param ctx - Request context\n * @returns Log-friendly context object\n */\nexport function contextForLogging(ctx: RequestContext): Record<string, unknown> {\n return {\n requestId: ctx.requestId,\n toolName: ctx.toolName,\n trustTier: ctx.trustTier,\n ...(ctx.caller.clientId !== undefined && { clientId: ctx.caller.clientId }),\n ...(ctx.traceId !== undefined && { traceId: ctx.traceId }),\n };\n}\n\n/**\n * Type guard to check if a value is a valid RequestContext.\n */\nexport function isRequestContext(value: unknown): value is RequestContext {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const obj = value as Record<string, unknown>;\n return (\n typeof obj['requestId'] === 'string' &&\n obj['requestId'].startsWith('req_') &&\n typeof obj['timestamp'] === 'string' &&\n typeof obj['toolName'] === 'string' &&\n typeof obj['caller'] === 'object' &&\n typeof obj['trustTier'] === 'string' &&\n ['1', '2', '3', '4'].includes(obj['trustTier'])\n );\n}\n","/**\n * nexus-agents/mcp - Tool Input Sanitizer Middleware\n *\n * Lightweight sanitization for MCP tool arguments. Strips XML-like\n * conversation injection tags and detects prompt injection patterns\n * in all string values within tool arguments.\n *\n * Defense-in-depth layer that protects against prompt injection\n * through tool arguments containing external content.\n *\n * @module mcp/middleware/tool-input-sanitizer\n * (Source: Issue #828 — Wire security modules into production pipeline)\n */\n\nimport type { ILogger } from '../../core/index.js';\n\n/**\n * Result of sanitizing tool input.\n */\nexport interface SanitizeToolInputResult {\n /** Sanitized arguments (XML tags stripped from string values) */\n readonly sanitized: unknown;\n /** Whether any modification was made */\n readonly wasModified: boolean;\n /** Count of strings that were modified */\n readonly modifiedCount: number;\n /** Injection patterns detected (for logging) */\n readonly detectedPatterns: readonly string[];\n}\n\n/**\n * XML-like tags that mimic conversation structure or system prompts.\n * Stripping these prevents prompt injection through tool arguments.\n */\nconst XML_INJECTION_PATTERN =\n /<\\/?(system|human|assistant|instructions|user|prompt|context|tool_use|tool_result)\\b[^>]*>/gi;\n\n/**\n * Patterns that indicate attempted prompt injection.\n * These are logged but not necessarily stripped (detection only).\n */\nconst INJECTION_DETECTORS: ReadonlyArray<{ name: string; pattern: RegExp }> = [\n { name: 'system_prompt_override', pattern: /ignore (?:all )?previous (?:instructions|rules)/i },\n { name: 'role_impersonation', pattern: /i(?:'m| am) the (?:repo |project )?(?:owner|admin)/i },\n { name: 'hidden_instruction', pattern: /<!--[\\s\\S]*?(?:execute|delete|merge|apply)[\\s\\S]*?-->/i },\n];\n\n/**\n * Sanitizes a single string value by stripping XML injection tags.\n * Returns the cleaned string and whether it was modified.\n */\nfunction sanitizeString(value: string): { cleaned: string; modified: boolean } {\n XML_INJECTION_PATTERN.lastIndex = 0;\n const cleaned = value.replace(XML_INJECTION_PATTERN, '');\n return { cleaned, modified: cleaned !== value };\n}\n\n/**\n * Detects injection patterns in a string without modifying it.\n */\nfunction detectPatterns(value: string): string[] {\n const detected: string[] = [];\n for (const { name, pattern } of INJECTION_DETECTORS) {\n pattern.lastIndex = 0;\n if (pattern.test(value)) {\n detected.push(name);\n }\n }\n return detected;\n}\n\n/**\n * Recursively sanitizes all string values in an object/array.\n * Returns a deep copy with XML injection tags stripped from strings.\n */\nfunction sanitizeValue(value: unknown, stats: { count: number; patterns: string[] }): unknown {\n if (typeof value === 'string') {\n const patterns = detectPatterns(value);\n if (patterns.length > 0) {\n stats.patterns.push(...patterns);\n }\n const { cleaned, modified } = sanitizeString(value);\n if (modified) stats.count++;\n return cleaned;\n }\n\n if (Array.isArray(value)) {\n return value.map((item) => sanitizeValue(item, stats));\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n result[key] = sanitizeValue(val, stats);\n }\n return result;\n }\n\n return value;\n}\n\n/**\n * Sanitizes MCP tool arguments by stripping XML injection tags\n * from all string values and detecting injection patterns.\n *\n * @param args - Tool arguments to sanitize\n * @returns Sanitized result with modification tracking\n */\nexport function sanitizeToolInput(args: unknown): SanitizeToolInputResult {\n if (args === undefined || args === null) {\n return { sanitized: args, wasModified: false, modifiedCount: 0, detectedPatterns: [] };\n }\n\n const stats = { count: 0, patterns: [] as string[] };\n const sanitized = sanitizeValue(args, stats);\n const uniquePatterns = [...new Set(stats.patterns)];\n\n return {\n sanitized,\n wasModified: stats.count > 0,\n modifiedCount: stats.count,\n detectedPatterns: uniquePatterns,\n };\n}\n\n/**\n * Logs sanitization results when modifications or detections occur.\n */\nexport function logSanitizationResult(\n result: SanitizeToolInputResult,\n logger: ILogger,\n toolName: string\n): void {\n if (result.wasModified) {\n logger.warn('Tool input sanitized — XML injection tags stripped', {\n tool: toolName,\n modifiedFields: result.modifiedCount,\n });\n }\n if (result.detectedPatterns.length > 0) {\n logger.warn('Injection patterns detected in tool input', {\n tool: toolName,\n patterns: result.detectedPatterns,\n });\n }\n}\n","/**\n * nexus-agents/mcp - Secure Handler Middleware\n *\n * Higher-order function that wraps MCP tool handlers with security middleware:\n * - RequestContext creation and tracking\n * - PolicyFirewall evaluation\n * - Logging with request context\n *\n * (Source: Issue #185 Phase 1 - PolicyFirewall integration)\n *\n * @module mcp/middleware/secure-handler\n */\n\nimport type { ILogger } from '../../core/index.js';\nimport { createLogger, getTimeProvider } from '../../core/index.js';\nimport {\n createRequestContext,\n contextForLogging,\n type RequestContext,\n type CallerInfo,\n} from './request-context.js';\nimport { type IPolicyFirewall, type ExecutionMode, createPolicyContext } from './policy.js';\nimport type { RateLimiter } from './rate-limiter.js';\nimport type { IAuditLogger } from '../../audit/audit-types.js';\nimport { actorFromContext, resultToOutcome } from '../../audit/secure-handler-audit.js';\nimport {\n sanitizeToolInput,\n logSanitizationResult,\n type SanitizeToolInputResult,\n} from './tool-input-sanitizer.js';\nimport { toolStructuredError, type ToolResult } from '../tools/tool-result.js';\n\nexport type { ToolResult };\n\n/**\n * Tool handler function signature.\n */\nexport type ToolHandler = (args: unknown) => Promise<ToolResult>;\n\n/**\n * Security tier for MCP tools. Controls input validation strictness.\n *\n * - 'standard': Default. XML injection tag stripping only (existing behavior).\n * - 'user-facing': Accepts user task descriptions. Rejects known injection patterns.\n * - 'external': Processes external URLs/content. Strictest validation.\n *\n * @see Issue #1586 — Tiered security validation\n */\nexport type SecurityTier = 'standard' | 'user-facing' | 'external';\n\n/**\n * Configuration for the secure handler wrapper.\n */\nexport interface SecureHandlerConfig {\n /** Tool name for logging and policy evaluation */\n toolName: string;\n /** Security tier controlling input validation strictness (default: 'standard') */\n securityTier?: SecurityTier;\n /** Policy firewall instance (optional - if not provided, policy checks are skipped) */\n policyFirewall?: IPolicyFirewall;\n /** Execution mode for policy evaluation */\n executionMode?: ExecutionMode;\n /** Allowed paths for file operations */\n allowedPaths?: readonly string[];\n /** Rate limiter instance (optional) */\n rateLimiter?: RateLimiter;\n /** Logger instance (optional - creates default if not provided) */\n logger?: ILogger;\n /** Caller information extractor (optional) */\n callerInfo?: CallerInfo;\n /** Audit logger for structured audit trail (Issue #740 Phase 2) */\n auditLogger?: IAuditLogger;\n}\n\n/**\n * Extended handler context passed to the wrapped handler.\n */\nexport interface HandlerContext {\n /** Request context for this invocation */\n requestContext: RequestContext;\n /** Logger with request context attached */\n logger: ILogger;\n}\n\n/**\n * Tool handler with context signature.\n */\nexport type ContextAwareHandler = (args: unknown, ctx: HandlerContext) => Promise<ToolResult>;\n\n/**\n * Creates a rate limit error response. Rate limits are transient — the\n * structured envelope marks it retryable (#2649).\n */\nfunction rateLimitError(nextTokenMs: number): ToolResult {\n return toolStructuredError({\n errorCategory: 'transient',\n message: `Rate limit exceeded. Try again in ${String(nextTokenMs)}ms.`,\n });\n}\n\n/**\n * Creates a policy denial error response — an access-control denial,\n * categorized `permission` (#2649).\n */\nfunction policyDeniedError(reason: string, requestId: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'permission',\n message: `Policy denied: ${reason} (request: ${requestId})`,\n });\n}\n\n/**\n * Creates an internal error response (#2649).\n */\nfunction internalError(message: string, requestId: string): ToolResult {\n return toolStructuredError({\n errorCategory: 'internal',\n message: `Internal error: ${message} (request: ${requestId})`,\n });\n}\n\n/**\n * Maximum input size for tool arguments (10MB).\n * Prevents memory exhaustion from oversized payloads.\n * (Source: Issue #740 - MCP security hardening)\n */\nconst MAX_INPUT_SIZE_BYTES = 10 * 1024 * 1024;\n\n/**\n * Patterns that indicate leaked secrets in tool output.\n * Each pattern is tested against tool response text.\n */\n// #3109: every pattern is GLOBAL so `replace` redacts ALL matches, not just\n// the first — two secrets of the same shape (e.g. a rotated old+new key) must\n// both be redacted before the result reaches the MCP caller.\nconst SECRET_PATTERNS: readonly RegExp[] = [\n // API keys with common prefixes\n /\\b(sk-[a-zA-Z0-9]{20,})\\b/g,\n /\\b(pk-[a-zA-Z0-9]{20,})\\b/g,\n // AWS-style keys\n /\\b(AKIA[A-Z0-9]{16})\\b/g,\n // Bearer tokens in output\n /Bearer\\s+[a-zA-Z0-9_\\-.~+/]+=*/g,\n // Generic long hex secrets (40+ chars)\n /\\b[0-9a-f]{40,}\\b/gi,\n // password= or token= in output\n /(?:password|token|secret|apikey|api_key)\\s*[=:]\\s*\\S{8,}/gi,\n];\n\n/** Redact detected secrets from tool output text. */\nfunction sanitizeOutput(text: string, logger: ILogger): string {\n let sanitized = text;\n for (const pattern of SECRET_PATTERNS) {\n // #3109: replace unconditionally — do NOT guard with pattern.test(), which\n // advances a global regex's lastIndex and makes replace() skip earlier\n // matches. `String.replace` with a global regex redacts every occurrence\n // and resets lastIndex to 0 on completion, so the shared pattern stays\n // safe across calls. Detect a redaction via a before/after compare.\n const before = sanitized;\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n if (sanitized !== before) {\n logger.warn('Potential secret detected in tool output, redacting', {\n pattern: pattern.source.slice(0, 30),\n });\n }\n }\n return sanitized;\n}\n\n/** Sanitize all text content in a tool result (Issue #740). */\nfunction sanitizeToolResult(result: ToolResult, logger: ILogger): void {\n for (const item of result.content) {\n item.text = sanitizeOutput(item.text, logger);\n }\n}\n\n/** Validates input size and returns error if too large. */\nfunction checkInputSize(args: unknown, logger: ILogger, requestId: string): ToolResult | null {\n if (args === undefined) return null;\n const inputSize = JSON.stringify(args).length;\n if (inputSize > MAX_INPUT_SIZE_BYTES) {\n logger.warn('Input size exceeds limit', { inputSize, limit: MAX_INPUT_SIZE_BYTES });\n return internalError('Input too large', requestId);\n }\n return null;\n}\n\n/**\n * Checks rate limiter and returns error if exceeded.\n */\nfunction checkRateLimit(rateLimiter: RateLimiter, logger: ILogger): ToolResult | null {\n const acquired = rateLimiter.tryAcquire();\n if (!acquired) {\n const state = rateLimiter.getState();\n logger.warn('Rate limit exceeded');\n return rateLimitError(state.nextTokenMs);\n }\n return null;\n}\n\n/** Options for policy check */\ninterface PolicyCheckOptions {\n firewall: IPolicyFirewall;\n toolName: string;\n args: unknown;\n mode: ExecutionMode;\n allowedPaths?: readonly string[] | undefined;\n logger: ILogger;\n requestId: string;\n}\n\n/**\n * Evaluates policy firewall and returns error if denied.\n */\nfunction checkPolicy(opts: PolicyCheckOptions): ToolResult | null {\n const ctxOpts = {\n mode: opts.mode,\n ...(opts.allowedPaths && { allowedPaths: opts.allowedPaths }),\n };\n const decision = opts.firewall.evaluate(createPolicyContext(opts.toolName, opts.args, ctxOpts));\n\n if (!decision.allowed) {\n opts.logger.warn('Policy denied tool execution', {\n reason: decision.reason,\n ruleName: decision.ruleName,\n });\n return policyDeniedError(decision.reason, opts.requestId);\n }\n opts.logger.debug('Policy check passed', { reason: decision.reason });\n return null;\n}\n\n/**\n * Executes handler and logs result.\n */\nasync function executeHandler(\n handler: ToolHandler | ContextAwareHandler,\n args: unknown,\n ctx: HandlerContext,\n logger: ILogger\n): Promise<ToolResult> {\n const startTime = getTimeProvider().now();\n const result =\n handler.length >= 2 ? await handler(args, ctx) : await (handler as ToolHandler)(args);\n\n const durationMs = getTimeProvider().now() - startTime;\n if (result.isError === true) {\n logger.warn('Tool execution completed with error', { durationMs });\n } else {\n logger.info('Tool execution completed', { durationMs });\n }\n return result;\n}\n\n/** Emits an audit event for a completed tool invocation. */\nfunction emitToolAudit(\n auditLogger: IAuditLogger,\n toolName: string,\n ctx: RequestContext,\n result: ToolResult,\n durationMs: number\n): void {\n const actor = actorFromContext(ctx);\n const outcome = resultToOutcome(result.isError, false);\n auditLogger.logToolInvocation({\n toolName,\n outcome,\n actor,\n requestId: ctx.requestId,\n durationMs,\n });\n}\n\n/**\n * Emits an audit event when a tool handler throws (or returns a rejected\n * Promise) — closes the audit-trail gap where unexpected exceptions left\n * no auditor record (security-review fallout from #2191).\n */\nfunction emitToolAuditException(\n auditLogger: IAuditLogger,\n toolName: string,\n ctx: RequestContext,\n durationMs: number\n): void {\n const actor = actorFromContext(ctx);\n auditLogger.logToolInvocation({\n toolName,\n outcome: 'error',\n actor,\n requestId: ctx.requestId,\n durationMs,\n });\n}\n\n/** Emits an audit event for a policy denial. */\nfunction emitPolicyAudit(\n auditLogger: IAuditLogger,\n toolName: string,\n ctx: RequestContext,\n reason: string\n): void {\n const actor = actorFromContext(ctx);\n auditLogger.logPolicyDecision({\n policyName: 'default',\n decision: 'deny',\n reason,\n toolName,\n actor,\n requestId: ctx.requestId,\n });\n}\n\n/** Emits an audit event for a rate limit violation. */\nfunction emitRateLimitAudit(\n auditLogger: IAuditLogger,\n toolName: string,\n ctx: RequestContext\n): void {\n const actor = actorFromContext(ctx);\n auditLogger.logRateLimitViolation({\n toolName,\n actor,\n currentRate: 0,\n limitRate: 0,\n requestId: ctx.requestId,\n });\n}\n\n/** Reject inputs with detected injection patterns for elevated security tiers. */\nfunction checkSecurityTier(\n config: SecureHandlerConfig,\n sanitizeResult: SanitizeToolInputResult,\n logger: ILogger\n): ToolResult | null {\n const tier = config.securityTier ?? 'standard';\n if (tier === 'standard' || sanitizeResult.detectedPatterns.length === 0) {\n return null;\n }\n logger.warn('Input rejected by security tier validation', {\n tier,\n patterns: sanitizeResult.detectedPatterns,\n });\n // Security-tier rejection of suspected injection patterns — an\n // access-control denial, categorized `permission` (#2649).\n return toolStructuredError({\n errorCategory: 'permission',\n message:\n `Input validation failed: detected patterns [${sanitizeResult.detectedPatterns.join(', ')}]. ` +\n 'Remove prompt injection patterns and retry.',\n });\n}\n\n/** Pre-execution checks: input size, input sanitization, rate limit, policy. */\nfunction runPreChecks(\n config: SecureHandlerConfig,\n args: unknown,\n mode: ExecutionMode,\n requestContext: RequestContext,\n logger: ILogger\n): { error: ToolResult | null; sanitizedArgs: unknown } {\n const sizeResult = checkInputSize(args, logger, requestContext.requestId);\n if (sizeResult) return { error: sizeResult, sanitizedArgs: args };\n\n // Sanitize tool input: strip XML injection tags, detect injection patterns (Issue #828)\n const sanitizeResult = sanitizeToolInput(args);\n logSanitizationResult(sanitizeResult, logger, config.toolName);\n const sanitizedArgs = sanitizeResult.wasModified ? sanitizeResult.sanitized : args;\n\n // Tiered validation: reject (not strip) for user-facing/external tools (Issue #1586)\n const tierError = checkSecurityTier(config, sanitizeResult, logger);\n if (tierError !== null) return { error: tierError, sanitizedArgs };\n\n if (config.rateLimiter) {\n const rlResult = checkRateLimit(config.rateLimiter, logger);\n if (rlResult) {\n if (config.auditLogger)\n emitRateLimitAudit(config.auditLogger, config.toolName, requestContext);\n return { error: rlResult, sanitizedArgs };\n }\n }\n\n if (config.policyFirewall) {\n const pResult = checkPolicy({\n firewall: config.policyFirewall,\n toolName: config.toolName,\n args: sanitizedArgs,\n mode,\n allowedPaths: config.allowedPaths,\n logger,\n requestId: requestContext.requestId,\n });\n if (pResult) {\n if (config.auditLogger)\n emitPolicyAudit(config.auditLogger, config.toolName, requestContext, 'policy denied');\n return { error: pResult, sanitizedArgs };\n }\n }\n\n return { error: null, sanitizedArgs };\n}\n\n/**\n * Wraps a tool handler with security middleware.\n *\n * @param handler - The original tool handler or context-aware handler\n * @param config - Security configuration\n * @returns Wrapped handler with security middleware\n */\nexport function createSecureHandler(\n handler: ToolHandler | ContextAwareHandler,\n config: SecureHandlerConfig\n): ToolHandler {\n const logger = config.logger ?? createLogger({ tool: config.toolName });\n const mode = config.executionMode ?? 'read-only';\n\n return async (args: unknown): Promise<ToolResult> => {\n const ctxOpts = {\n toolName: config.toolName,\n ...(config.callerInfo && { caller: config.callerInfo }),\n };\n const requestContext = createRequestContext(ctxOpts);\n const requestLogger = logger.child(contextForLogging(requestContext));\n requestLogger.info('Tool invocation started');\n\n const { error: preCheckError, sanitizedArgs } = runPreChecks(\n config,\n args,\n mode,\n requestContext,\n requestLogger\n );\n if (preCheckError) return preCheckError;\n\n return executeAndAudit(handler, sanitizedArgs, requestContext, requestLogger, config);\n };\n}\n\n/**\n * Executes the wrapped handler with audit emission on both the success and\n * exception paths. Extracted from `createSecureHandler` to keep that\n * function within the 50-line budget.\n */\nasync function executeAndAudit(\n handler: ToolHandler | ContextAwareHandler,\n sanitizedArgs: unknown,\n requestContext: RequestContext,\n requestLogger: ILogger,\n config: SecureHandlerConfig\n): Promise<ToolResult> {\n const execStartTime = getTimeProvider().now();\n try {\n const result = await executeHandler(\n handler,\n sanitizedArgs,\n { requestContext, logger: requestLogger },\n requestLogger\n );\n sanitizeToolResult(result, requestLogger);\n if (config.auditLogger) {\n emitToolAudit(\n config.auditLogger,\n config.toolName,\n requestContext,\n result,\n getTimeProvider().now() - execStartTime\n );\n }\n return result;\n } catch (error) {\n const rawMessage = error instanceof Error ? error.message : 'Unknown error';\n requestLogger.error('Tool execution failed', error instanceof Error ? error : undefined);\n if (config.auditLogger) {\n emitToolAuditException(\n config.auditLogger,\n config.toolName,\n requestContext,\n getTimeProvider().now() - execStartTime\n );\n }\n // Closes a secret-leak path: adapter SDKs commonly echo offending\n // credentials in their error messages (e.g. Anthropic's\n // AuthenticationError carries `sk-ant-api03-…` substrings; fetch\n // wrappers can echo Authorization headers). The success branch above\n // runs sanitizeToolResult; the exception path must too.\n const sanitized = sanitizeOutput(rawMessage, requestLogger);\n return internalError(sanitized, requestContext.requestId);\n }\n}\n\n/**\n * Creates a secure handler factory with shared configuration.\n * Useful for registering multiple tools with the same security settings.\n *\n * @param sharedConfig - Shared security configuration\n * @returns Factory function for creating secure handlers\n */\nexport function createSecureHandlerFactory(\n sharedConfig: Omit<SecureHandlerConfig, 'toolName'>\n): (toolName: string, handler: ToolHandler | ContextAwareHandler) => ToolHandler {\n return (toolName: string, handler: ToolHandler | ContextAwareHandler) =>\n createSecureHandler(handler, { ...sharedConfig, toolName });\n}\n","/**\n * nexus-agents/mcp - MCP Notification Helper\n *\n * Sends structured logging notifications to MCP clients via\n * the `notifications/message` protocol method.\n * Clients (e.g., Claude Code) can display these for real-time\n * observability of orchestration events.\n *\n * Also provides progress notification support via AsyncLocalStorage\n * for resetting client-side request timeouts (MCP SDK resetTimeoutOnProgress).\n *\n * @module mcp/mcp-notifier\n * (Source: Issue #973, #974 — Claude Code Observability)\n * (Source: Issue #1108 — Progress heartbeat timeout reset)\n * (Source: MCP Protocol 2025-11-25, Logging Specification)\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { createLogger, getErrorMessage } from '../core/index.js';\n\n/**\n * Logging levels for MCP notifications (RFC 5424 syslog).\n */\nexport type McpLogLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error';\n\n/**\n * MCP notifier for sending structured log events to clients.\n */\nexport interface IMcpNotifier {\n /** Send info-level notification (key orchestration events) */\n info(logger: string, data: Record<string, unknown>): void;\n /** Send debug-level notification (detailed execution steps) */\n debug(logger: string, data: Record<string, unknown>): void;\n /** Send warning-level notification */\n warn(logger: string, data: Record<string, unknown>): void;\n}\n\nconst internalLogger = createLogger({ component: 'mcp-notifier' });\n\n/**\n * Creates an MCP notifier that sends logging notifications to connected clients.\n *\n * Notifications are fire-and-forget — failures are logged but never\n * propagate to callers. This ensures observability never breaks tool execution.\n */\nexport function createMcpNotifier(server: McpServer): IMcpNotifier {\n function send(level: McpLogLevel, logger: string, data: Record<string, unknown>): void {\n try {\n server.sendLoggingMessage({ level, logger, data }).catch((error: unknown) => {\n internalLogger.debug('Failed to send MCP notification', {\n level,\n logger,\n error: getErrorMessage(error),\n });\n });\n } catch (error: unknown) {\n internalLogger.debug('Failed to send MCP notification', {\n level,\n logger,\n error: getErrorMessage(error),\n });\n }\n }\n\n return {\n info: (logger, data) => {\n send('info', logger, data);\n },\n debug: (logger, data) => {\n send('debug', logger, data);\n },\n warn: (logger, data) => {\n send('warning', logger, data);\n },\n };\n}\n\n/**\n * No-op notifier for when MCP server is not available.\n */\nexport const NOOP_NOTIFIER: IMcpNotifier = {\n info: () => undefined,\n debug: () => undefined,\n warn: () => undefined,\n};\n\n// ============================================================================\n// Progress Notification Support (MCP SDK resetTimeoutOnProgress)\n// ============================================================================\n\n/**\n * Callback to send a progress notification to the MCP client.\n * When the client sets resetTimeoutOnProgress=true, each notification\n * resets the client's 60s request timeout.\n */\nexport type ProgressSender = (progress: number, total?: number) => void;\n\n/**\n * Progress context stored via AsyncLocalStorage.\n * Set by toSdkCallbackWithProgress when a progressToken is available.\n */\nexport interface ProgressContext {\n readonly progressToken: string | number;\n readonly sendNotification: ProgressSender;\n}\n\n/**\n * AsyncLocalStorage for MCP progress context.\n * Allows withProgressHeartbeat to access the progress sender without\n * threading it through the entire middleware chain.\n */\nexport const progressContextStorage = new AsyncLocalStorage<ProgressContext>();\n\n// ============================================================================\n// Abort Signal Support (MCP SDK cancellation)\n// ============================================================================\n\n/**\n * AsyncLocalStorage for MCP abort signal.\n * Set by toSdkCallback when the SDK provides an AbortSignal.\n * Allows middleware (e.g., TimeoutGuard) to race client cancellation\n * alongside server-side timeouts.\n */\nexport const abortSignalStorage = new AsyncLocalStorage<AbortSignal>();\n\n/**\n * Wraps an async operation with periodic heartbeat notifications.\n *\n * When a progressToken is available (via AsyncLocalStorage from the MCP\n * request handler), sends real `notifications/progress` that reset the\n * client's request timeout (MCP SDK resetTimeoutOnProgress feature).\n *\n * Always sends logging notifications for observability regardless.\n *\n * @param toolName - Name of the tool for notification context\n * @param notifier - MCP notifier instance\n * @param operation - The async operation to wrap\n * @param intervalMs - Heartbeat interval (default: 15000ms)\n * @returns The operation result\n */\nexport async function withProgressHeartbeat<T>(\n toolName: string,\n notifier: IMcpNotifier,\n operation: () => Promise<T>,\n intervalMs = 15_000\n): Promise<T> {\n const startTime = Date.now();\n let beatCount = 0;\n const progressCtx = progressContextStorage.getStore();\n\n const timer = setInterval(() => {\n beatCount++;\n const elapsed = Math.round((Date.now() - startTime) / 1000);\n\n // Send real progress notification if client provided progressToken\n if (progressCtx !== undefined) {\n progressCtx.sendNotification(beatCount);\n }\n\n // Always send logging notification for observability\n notifier.debug(toolName, {\n event: 'heartbeat',\n elapsedSeconds: elapsed,\n beatCount,\n hasProgressToken: progressCtx !== undefined,\n });\n }, intervalMs);\n\n try {\n return await operation();\n } finally {\n clearInterval(timer);\n }\n}\n","/**\n * nexus-agents/mcp - Tool Wrapper Helper\n *\n * Provides a convenient wrapper for MCP tools that automatically applies\n * the middleware chain with timeout protection (CVE-2026-0621 mitigation).\n *\n * @module mcp/middleware/tool-wrapper\n * (Source: Issue #271, CVE-2026-0621 mitigation)\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { appendFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nimport type { ILogger } from '../../core/index.js';\nimport type { TimeoutConfig, SecurityConfig } from '../../config/schemas.js';\nimport type { IPolicyFirewall, ExecutionMode } from './policy.js';\nimport type { RateLimiterConfig } from './rate-limiter.js';\nimport { RateLimiter } from './rate-limiter.js';\nimport {\n withMiddleware,\n createMiddlewareFactory,\n type ToolHandler,\n type ContextAwareToolHandler,\n type MiddlewareChainConfig,\n} from './middleware-chain.js';\nimport { MCP_TIMEOUTS, resolveToolClassGuardMs } from '../../config/timeouts.js';\nimport {\n progressContextStorage,\n abortSignalStorage,\n type ProgressContext,\n} from '../mcp-notifier.js';\nimport { createLogger as createInternalLogger, getErrorMessage } from '../../core/index.js';\nimport { getNexusDataDir } from '../../config/nexus-data-dir.js';\n\n/**\n * Default timeout configuration.\n * Values sourced from config/timeouts.ts (Issue #984).\n */\nexport const DEFAULT_TIMEOUT_CONFIG: TimeoutConfig = {\n defaultTimeoutMs: MCP_TIMEOUTS.defaultMs,\n maxTimeoutMs: MCP_TIMEOUTS.maxMs,\n enableLogging: true,\n uriValidation: true,\n};\n\n/**\n * Default per-tool timeout overrides.\n * Sourced from config/timeouts.ts (Issue #984).\n */\nexport const DEFAULT_TOOL_TIMEOUTS: Record<string, number> = {\n ...MCP_TIMEOUTS.perTool,\n};\n\n/**\n * Resolves the timeout for a specific tool — the central resolution chokepoint\n * (#3734). Lookup chain:\n * 1. explicit override (caller-supplied),\n * 2. security config `perToolTimeout`,\n * 3. the operation-class runaway-guard for the tool's {@link TOOL_CLASS}\n * classification (or {@link DEFAULT_OPERATION_CLASS} = 300s if unclassified),\n * honoring `NEXUS_TIMEOUT_MULTIPLIER` + per-class env overrides.\n *\n * The class-guard step replaces the old `DEFAULT_TOOL_TIMEOUTS` literal lookup\n * AND the punitive 60s global default — every tool now gets a generous\n * non-punitive runaway-guard.\n * (Issue #657 — per-tool timeout; #3734 — central class authority)\n */\nexport function getToolTimeout(\n toolName: string,\n security?: SecurityConfig,\n explicitMs?: number\n): number {\n // Explicit override takes highest priority.\n if (explicitMs !== undefined) {\n return explicitMs;\n }\n // Security config per-tool overrides still win over the class default.\n const perToolConfig = security?.timeout?.perToolTimeout;\n const perToolMs = perToolConfig?.[toolName];\n if (perToolMs !== undefined) {\n return perToolMs;\n }\n // Class-derived runaway-guard (multiplier + per-class env overrides applied).\n return resolveToolClassGuardMs(toolName);\n}\n\n/**\n * Configuration for creating a tool factory.\n */\nexport interface ToolFactoryConfig {\n /** Logger instance */\n logger?: ILogger | undefined;\n /** Security configuration (includes timeout config) */\n security?: SecurityConfig | undefined;\n /** Policy firewall instance */\n policyFirewall?: IPolicyFirewall | undefined;\n /** Rate limiter configuration */\n rateLimiter?: RateLimiterConfig | RateLimiter | undefined;\n /** Allowed paths for file operations */\n allowedPaths?: readonly string[] | undefined;\n}\n\n/**\n * Per-tool configuration options.\n */\nexport interface ToolWrapperOptions {\n /** Execution mode for policy evaluation (default: 'read-only') */\n executionMode?: ExecutionMode | undefined;\n /** Custom timeout in ms (overrides default) */\n timeoutMs?: number | undefined;\n /** Skip timeout protection (use sparingly) */\n skipTimeout?: boolean | undefined;\n /** Skip rate limiting */\n skipRateLimit?: boolean | undefined;\n}\n\n/**\n * Gets timeout configuration from security config or uses defaults.\n */\nfunction getTimeoutConfig(\n security?: SecurityConfig,\n overrideMs?: number\n): MiddlewareChainConfig['timeout'] {\n const timeoutConfig = security?.timeout ?? DEFAULT_TIMEOUT_CONFIG;\n\n return {\n defaultTimeoutMs: overrideMs ?? timeoutConfig.defaultTimeoutMs,\n maxTimeoutMs: timeoutConfig.maxTimeoutMs,\n enableLogging: timeoutConfig.enableLogging,\n };\n}\n\n/**\n * Creates a tool factory with shared configuration.\n *\n * This factory produces wrapped handlers that include timeout protection,\n * rate limiting, and other middleware as configured.\n *\n * @example\n * ```typescript\n * const wrapTool = createToolFactory({\n * security: appConfig.security,\n * rateLimiter: { capacity: 100, refillRate: 10 },\n * });\n *\n * const handler = wrapTool('my_tool', async (args) => {\n * // Your tool logic here\n * return { content: [{ type: 'text', text: 'Done' }] };\n * });\n * ```\n */\nexport function createToolFactory(\n config: ToolFactoryConfig\n): (\n toolName: string,\n handler: ContextAwareToolHandler | ToolHandler,\n options?: ToolWrapperOptions\n) => ToolHandler {\n const { security, policyFirewall, rateLimiter, allowedPaths, logger } = config;\n\n return (toolName, handler, options) => {\n const skip = {\n timeout: options?.skipTimeout,\n rateLimit: options?.skipRateLimit,\n };\n\n const chainConfig: Omit<MiddlewareChainConfig, 'toolName'> = {\n logger,\n policyFirewall,\n executionMode: options?.executionMode ?? 'read-only',\n allowedPaths,\n rateLimiter,\n timeout: skip.timeout === true ? undefined : getTimeoutConfig(security, options?.timeoutMs),\n skip,\n };\n\n return withMiddleware(toolName, handler, chainConfig);\n };\n}\n\n/**\n * Wraps a single tool handler with timeout protection.\n *\n * This is a convenience function for simple cases where you don't need\n * the full factory setup.\n *\n * @example\n * ```typescript\n * const handler = wrapToolWithTimeout('my_tool', async (args) => {\n * return { content: [{ type: 'text', text: 'Done' }] };\n * });\n * ```\n */\nexport function wrapToolWithTimeout(\n toolName: string,\n handler: ContextAwareToolHandler | ToolHandler,\n options?: {\n timeoutMs?: number;\n logger?: ILogger;\n }\n): ToolHandler {\n return withMiddleware(toolName, handler, {\n timeout: getTimeoutConfig(undefined, options?.timeoutMs),\n logger: options?.logger,\n });\n}\n\n/** Shape of the MCP SDK's extra._meta for progress tokens. */\ninterface SdkMeta {\n readonly progressToken?: string | number;\n}\n\n/** Shape of the MCP SDK's extra object passed to tool handlers. */\ninterface SdkExtra {\n readonly _meta?: SdkMeta;\n readonly signal?: AbortSignal;\n readonly sendNotification?: (notification: {\n method: string;\n params?: Record<string, unknown>;\n }) => Promise<void>;\n}\n\nconst wrapperLogger = createInternalLogger({ component: 'tool-wrapper' });\n\n/** Extract progress context from MCP SDK extra if progressToken present. */\nfunction extractProgressContext(extra: unknown): ProgressContext | undefined {\n const sdk = extra as SdkExtra | undefined;\n const token = sdk?._meta?.progressToken;\n const sendFn = sdk?.sendNotification;\n if (token === undefined || sendFn === undefined) return undefined;\n\n return {\n progressToken: token,\n sendNotification: (progress: number, total?: number) => {\n const params: Record<string, unknown> = {\n progressToken: token,\n progress,\n };\n if (total !== undefined) params['total'] = total;\n sendFn({ method: 'notifications/progress', params }).catch((err: unknown) => {\n wrapperLogger.debug('Failed to send progress notification', {\n error: getErrorMessage(err),\n });\n });\n },\n };\n}\n\n/**\n * Runs handler within nested AsyncLocalStorage contexts for progress + abort.\n */\n/** SDK-compatible tool result with optional structuredContent (Issue #1117). */\ntype SdkToolResult = {\n content: Array<{ type: 'text'; text: string }>;\n isError?: boolean;\n structuredContent?: Record<string, unknown>;\n // Post-#2649: the structured error envelope lives in `_meta` under\n // `nexus-agents/error` (not in `structuredContent`, which is validated\n // against `outputSchema` even on error results).\n _meta?: Record<string, unknown>;\n};\n\nfunction runWithContexts(\n handler: ToolHandler,\n args: unknown,\n progressCtx: ProgressContext | undefined,\n signal: AbortSignal | undefined\n): Promise<SdkToolResult> {\n const run = (): Promise<SdkToolResult> => handler(args);\n\n // Nest contexts: abort signal outer, progress inner\n if (signal !== undefined && progressCtx !== undefined) {\n return abortSignalStorage.run(signal, () => progressContextStorage.run(progressCtx, run));\n }\n if (signal !== undefined) {\n return abortSignalStorage.run(signal, run);\n }\n if (progressCtx !== undefined) {\n return progressContextStorage.run(progressCtx, run);\n }\n return run();\n}\n\n/**\n * Adapts a ToolHandler to the MCP SDK's expected callback signature.\n *\n * Extracts progressToken and AbortSignal from extra, runs the handler\n * within AsyncLocalStorage contexts so middleware can access them.\n *\n * @param handler - Our internal ToolHandler\n * @returns SDK-compatible callback function\n */\nexport function toSdkCallback(\n handler: ToolHandler\n): (args: unknown, extra: unknown) => Promise<SdkToolResult> {\n return (args: unknown, extra: unknown) => {\n const progressCtx = extractProgressContext(extra);\n const signal = (extra as SdkExtra | undefined)?.signal;\n return runWithContexts(handler, args, progressCtx, signal);\n };\n}\n\n/**\n * MCP SDK client default request timeout. Matches `DEFAULT_REQUEST_TIMEOUT_MSEC`\n * in `@modelcontextprotocol/sdk` (`shared/protocol.js`). If a tool's\n * configured server-side budget exceeds this and the client did not send a\n * `progressToken` (i.e. did not pass `onprogress` to its `request()` call),\n * the client kills the request at this threshold regardless of what the\n * server is doing — heartbeats fire but go nowhere.\n *\n * (Source: audit on #2619 / #2631 — root cause of \"MCP error -32001 at 60010ms\")\n */\nexport const MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS = 60_000;\n\n/**\n * Relative path under `$NEXUS_DATA_DIR` for the timeout-mismatch event log.\n * The #2632 WARN was log-only — useful in tail but not queryable. #2703\n * records each mismatch event as a JSONL row keyed by a correlation\n * `eventId` shared with the log entry, so \"did mismatch cause this\n * timeout?\" can be answered by joining the warning's eventId against the\n * recorded outcome — not just counted in aggregate.\n *\n * Schema lives at `docs/architecture/MCP_PROTOCOL.md` (Timeout-mismatch\n * telemetry section).\n */\nexport const TIMEOUT_MISMATCH_TELEMETRY_REL_PATH = 'mcp-telemetry/timeout-mismatch-events.jsonl';\n\n/** A single timeout-mismatch event recorded to the telemetry JSONL. */\nexport interface TimeoutMismatchEvent {\n readonly eventId: string;\n readonly toolName: string;\n readonly configuredTimeoutMs: number;\n readonly mcpSdkDefaultMs: number;\n readonly startedAt: string;\n readonly endedAt: string;\n readonly durationMs: number;\n readonly outcome: 'success' | 'error';\n /** From the post-#2649 structured error envelope when present. */\n readonly errorCategory?: string;\n readonly errorMessage?: string;\n}\n\n/**\n * Cache the \"dir ensured\" flag so we don't re-`existsSync` on every call\n * (closes #2955 site 3, partial). Cached per `dirname(path)` so an\n * operator changing `NEXUS_DATA_DIR` between calls (test/dev only)\n * still works after a process restart. The full async-write part of\n * the perf fix is deferred — `tool-wrapper-budget-check.test.ts` reads\n * the JSONL synchronously after `await callback(...)` and expects the\n * write to be visible, so switching to `fs.promises.appendFile` broke\n * those tests. The dir-cache is the cheaper part of the perf win\n * (skipping 1 existsSync per call); the appendFileSync vs appendFile\n * win can ship later behind a test-helper that awaits pending writes.\n */\nconst ensuredDirs = new Set<string>();\n\n/** Best-effort append — telemetry recording must never fail the user's tool call. */\nfunction appendTimeoutMismatchEvent(event: TimeoutMismatchEvent): void {\n try {\n const path = join(getNexusDataDir(), TIMEOUT_MISMATCH_TELEMETRY_REL_PATH);\n const dir = dirname(path);\n if (!ensuredDirs.has(dir)) {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n ensuredDirs.add(dir);\n }\n appendFileSync(path, JSON.stringify(event) + '\\n', 'utf-8');\n } catch (err) {\n wrapperLogger.debug('Best-effort timeout-mismatch event recording failed', {\n error: getErrorMessage(err),\n });\n }\n}\n\n/** Pull the post-#2649 errorCategory off an error result's `_meta` envelope. */\nfunction extractErrorCategoryFromResult(result: SdkToolResult): string | undefined {\n const envelope = result._meta?.['nexus-agents/error'];\n if (envelope !== null && typeof envelope === 'object' && 'errorCategory' in envelope) {\n const cat = (envelope as { errorCategory?: unknown }).errorCategory;\n if (typeof cat === 'string') return cat;\n }\n return undefined;\n}\n\n/** First text-content line of an error result, truncated for logging. */\nfunction extractErrorMessageFromResult(result: SdkToolResult): string | undefined {\n const first = result.content[0];\n if (first?.type === 'text' && typeof first.text === 'string') {\n return first.text.slice(0, 500);\n }\n return undefined;\n}\n\ninterface MismatchCallContext {\n readonly log: ILogger;\n readonly handler: ToolHandler;\n readonly args: unknown;\n readonly progressCtx: ProgressContext | undefined;\n readonly signal: AbortSignal | undefined;\n readonly toolName: string;\n readonly configuredTimeoutMs: number;\n}\n\ninterface MismatchOutcome {\n readonly outcome: 'success' | 'error';\n readonly errorCategory?: string;\n readonly errorMessage?: string;\n}\n\n/** Build a complete event record from a finished mismatched call. */\nfunction buildMismatchEvent(\n ctx: MismatchCallContext,\n eventId: string,\n t0: number,\n outcome: MismatchOutcome\n): TimeoutMismatchEvent {\n const t1 = Date.now();\n return {\n eventId,\n toolName: ctx.toolName,\n configuredTimeoutMs: ctx.configuredTimeoutMs,\n mcpSdkDefaultMs: MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS,\n startedAt: new Date(t0).toISOString(),\n endedAt: new Date(t1).toISOString(),\n durationMs: t1 - t0,\n outcome: outcome.outcome,\n ...(outcome.errorCategory !== undefined ? { errorCategory: outcome.errorCategory } : {}),\n ...(outcome.errorMessage !== undefined ? { errorMessage: outcome.errorMessage } : {}),\n };\n}\n\n/** Classify a tool result into a MismatchOutcome (success or structured error). */\nfunction classifyResult(result: SdkToolResult): MismatchOutcome {\n if (result.isError !== true) return { outcome: 'success' };\n const errorCategory = extractErrorCategoryFromResult(result);\n const errorMessage = extractErrorMessageFromResult(result);\n return {\n outcome: 'error',\n ...(errorCategory !== undefined ? { errorCategory } : {}),\n ...(errorMessage !== undefined ? { errorMessage } : {}),\n };\n}\n\n/** Run a mismatched call, recording its outcome to the JSONL. */\nasync function runMismatchedCall(ctx: MismatchCallContext): Promise<SdkToolResult> {\n const eventId = randomUUID();\n const t0 = Date.now();\n ctx.log.warn(\n 'MCP tool budget exceeds client default and no progressToken received — request likely to be killed by client before server-side deadline',\n {\n tool: ctx.toolName,\n eventId,\n configuredTimeoutMs: ctx.configuredTimeoutMs,\n mcpSdkDefaultMs: MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS,\n remediation:\n 'Client should pass `onprogress` and `resetTimeoutOnProgress: true` when calling, or extend `options.timeout`. See docs/architecture/MCP_PROTOCOL.md.',\n }\n );\n try {\n const result = await runWithContexts(ctx.handler, ctx.args, ctx.progressCtx, ctx.signal);\n appendTimeoutMismatchEvent(buildMismatchEvent(ctx, eventId, t0, classifyResult(result)));\n return result;\n } catch (err) {\n appendTimeoutMismatchEvent(\n buildMismatchEvent(ctx, eventId, t0, {\n outcome: 'error',\n errorMessage: getErrorMessage(err).slice(0, 500),\n })\n );\n throw err;\n }\n}\n\n/**\n * Like `toSdkCallback`, but emits a one-shot WARN at invocation start when\n * the configured per-tool budget exceeds the MCP SDK client default AND the\n * client did not send a `progressToken`. The call is almost certainly going\n * to die at the client default (~60s) regardless of server-side timeout\n * config or progress heartbeats — surface that at the moment of invocation\n * so operators can spot the mismatch in logs without waiting for the\n * timeout to fire.\n *\n * Wrap a long-running tool (`orchestrate`, `consensus_vote`,\n * `execute_expert`, `run_workflow`) with this instead of plain\n * `toSdkCallback`. Tools whose budget already fits within\n * `MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS` should keep using `toSdkCallback`.\n *\n * Each mismatch is **also recorded** to\n * `$NEXUS_DATA_DIR/mcp-telemetry/timeout-mismatch-events.jsonl` with a\n * correlation `eventId` (also surfaced in the WARN log entry) and the\n * call's eventual outcome (`success` / `error` + post-#2649 errorCategory\n * if present). This lets the Epic #2631 gate be answered with data —\n * \"of N mismatches, what fraction ended in a timeout?\" — not just counted\n * in aggregate (#2703).\n *\n * (Source: audit on #2619 / #2631 — observability for client-timeout mismatch)\n */\nexport function toSdkCallbackWithBudgetCheck(\n handler: ToolHandler,\n toolName: string,\n configuredTimeoutMs: number,\n logger?: ILogger\n): (args: unknown, extra: unknown) => Promise<SdkToolResult> {\n const log = logger ?? wrapperLogger;\n return (args: unknown, extra: unknown) => {\n const progressCtx = extractProgressContext(extra);\n const signal = (extra as SdkExtra | undefined)?.signal;\n const isMismatch =\n configuredTimeoutMs > MCP_SDK_DEFAULT_REQUEST_TIMEOUT_MS && progressCtx === undefined;\n if (!isMismatch) return runWithContexts(handler, args, progressCtx, signal);\n return runMismatchedCall({\n log,\n handler,\n args,\n progressCtx,\n signal,\n toolName,\n configuredTimeoutMs,\n });\n };\n}\n\n/**\n * Re-export middleware factory for advanced use cases.\n */\nexport { createMiddlewareFactory, withMiddleware };\n","/**\n * nexus-agents/mcp - Timeout Guard Middleware\n *\n * Provides timeout protection for MCP operations to mitigate ReDoS and\n * other denial-of-service vectors. Implements configurable timeouts with\n * proper cleanup and error handling.\n *\n * (Source: CVE-2026-0621, GHSA-8r9q-7v3j-jr4g)\n * (Source: Issue #107)\n *\n * @module mcp/middleware/timeout-guard\n */\n\nimport {\n getErrorMessage,\n createLogger,\n type ILogger,\n type Result,\n ok,\n err,\n getTimeProvider,\n} from '../../core/index.js';\n\n/**\n * Error codes for timeout-related failures.\n */\nexport type TimeoutErrorCode =\n | 'OPERATION_TIMEOUT'\n | 'OPERATION_CANCELLED'\n | 'INVALID_TIMEOUT'\n | 'GUARD_ERROR';\n\n/**\n * Timeout guard error.\n */\nexport interface TimeoutError {\n readonly code: TimeoutErrorCode;\n readonly message: string;\n readonly operation?: string;\n readonly timeoutMs?: number;\n readonly cause?: Error;\n}\n\n/**\n * Configuration for timeout guard.\n */\nexport interface TimeoutGuardConfig {\n /** Default timeout in milliseconds (default: 30000) */\n readonly defaultTimeoutMs?: number;\n /** Maximum allowed timeout in milliseconds (default: 300000) */\n readonly maxTimeoutMs?: number;\n /** Whether to log timeout events (default: true) */\n readonly enableLogging?: boolean;\n /** Logger instance */\n readonly logger?: ILogger;\n}\n\n/**\n * Result of a guarded operation.\n */\nexport interface GuardedResult<T> {\n /** The operation result */\n readonly value: T;\n /** Execution duration in milliseconds */\n readonly durationMs: number;\n /** Whether the operation was near timeout */\n readonly nearTimeout: boolean;\n}\n\n/** Execution options for guarded operations. */\nexport interface ExecuteOptions {\n /** Custom timeout for this operation */\n readonly timeoutMs?: number;\n /** Name for logging/debugging */\n readonly operationName?: string;\n /** Cleanup function to call on timeout */\n readonly onTimeout?: () => void;\n /** AbortSignal for client-initiated cancellation */\n readonly signal?: AbortSignal;\n}\n\n// Canonical source: config/timeouts.ts (Issue #1046)\nimport { TIMEOUT_GUARD } from '../../config/timeouts.js';\n\nconst DEFAULT_TIMEOUT_MS = TIMEOUT_GUARD.defaultMs;\nconst MAX_TIMEOUT_MS = TIMEOUT_GUARD.maxMs;\nconst NEAR_TIMEOUT_THRESHOLD = TIMEOUT_GUARD.nearTimeoutThreshold;\n\n/** Internal state for tracking timeout. */\ninterface TimeoutState {\n timeoutId: ReturnType<typeof setTimeout> | undefined;\n timedOut: boolean;\n}\n\n/**\n * Creates a timeout error for operation timeout.\n */\nfunction createTimeoutError(operationName: string, timeoutMs: number): TimeoutError {\n return {\n code: 'OPERATION_TIMEOUT',\n message: `Operation '${operationName}' timed out after ${String(timeoutMs)}ms`,\n operation: operationName,\n timeoutMs,\n };\n}\n\n/**\n * Creates a guard error from a caught exception.\n */\nfunction createGuardError(error: unknown, operationName: string): TimeoutError {\n const guardError: TimeoutError = {\n code: 'GUARD_ERROR',\n message: getErrorMessage(error),\n operation: operationName,\n };\n if (error instanceof Error) {\n return { ...guardError, cause: error };\n }\n return guardError;\n}\n\n/**\n * Timeout guard for protecting async operations from hanging.\n *\n * Provides protection against:\n * - ReDoS attacks (CVE-2026-0621)\n * - Slow/hanging external services\n * - Resource exhaustion\n *\n * @example\n * ```typescript\n * const guard = new TimeoutGuard({ defaultTimeoutMs: 5000 });\n *\n * const result = await guard.execute(\n * () => someAsyncOperation(),\n * { operationName: 'process-uri' }\n * );\n *\n * if (result.ok) {\n * console.log('Completed in', result.value.durationMs, 'ms');\n * }\n * ```\n */\nexport class TimeoutGuard {\n private readonly defaultTimeoutMs: number;\n private readonly maxTimeoutMs: number;\n private readonly enableLogging: boolean;\n private readonly logger: ILogger;\n\n constructor(config?: TimeoutGuardConfig) {\n this.defaultTimeoutMs = config?.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxTimeoutMs = config?.maxTimeoutMs ?? MAX_TIMEOUT_MS;\n this.enableLogging = config?.enableLogging ?? true;\n this.logger = config?.logger ?? createLogger({ component: 'timeout-guard' });\n }\n\n /** Resolves effective timeout and operation name from options. */\n private resolveOptions(options?: ExecuteOptions): {\n timeoutMs: number;\n operationName: string;\n } {\n return {\n timeoutMs: Math.min(options?.timeoutMs ?? this.defaultTimeoutMs, this.maxTimeoutMs),\n operationName: options?.operationName ?? 'unknown',\n };\n }\n\n /**\n * Executes an async operation with timeout protection.\n */\n async execute<T>(\n operation: () => Promise<T>,\n options?: ExecuteOptions\n ): Promise<Result<GuardedResult<T>, TimeoutError>> {\n const { timeoutMs, operationName } = this.resolveOptions(options);\n\n const validationError = this.validateTimeout(timeoutMs, operationName);\n if (validationError !== null) {\n return err(validationError);\n }\n\n return this.runGuarded(operation, timeoutMs, operationName, options);\n }\n\n /** Runs the operation with timeout and optional abort signal. */\n private async runGuarded<T>(\n operation: () => Promise<T>,\n timeoutMs: number,\n operationName: string,\n options?: ExecuteOptions\n ): Promise<Result<GuardedResult<T>, TimeoutError>> {\n this.logStart(operationName, timeoutMs);\n const startTime = getTimeProvider().now();\n const state: TimeoutState = { timeoutId: undefined, timedOut: false };\n\n try {\n const result = await this.runWithTimeout(\n operation,\n timeoutMs,\n state,\n options?.onTimeout,\n options?.signal\n );\n return this.handleSuccess(result, startTime, timeoutMs, operationName);\n } catch {\n const cancelled = options?.signal?.aborted === true && !state.timedOut;\n return err(\n this.handleFailure(state.timedOut, operationName, timeoutMs, startTime, cancelled)\n );\n } finally {\n if (state.timeoutId !== undefined) {\n clearTimeout(state.timeoutId);\n }\n }\n }\n\n private validateTimeout(timeoutMs: number, operationName: string): TimeoutError | null {\n if (timeoutMs <= 0) {\n return {\n code: 'INVALID_TIMEOUT',\n message: `Invalid timeout: ${String(timeoutMs)}ms`,\n operation: operationName,\n };\n }\n return null;\n }\n\n private logStart(operationName: string, timeoutMs: number): void {\n if (this.enableLogging) {\n this.logger.debug('Starting guarded operation', { operation: operationName, timeoutMs });\n }\n }\n\n private async runWithTimeout<T>(\n operation: () => Promise<T>,\n timeoutMs: number,\n state: TimeoutState,\n onTimeout?: () => void,\n signal?: AbortSignal\n ): Promise<T> {\n const timeoutPromise = new Promise<never>((_resolve, reject) => {\n state.timeoutId = setTimeout(() => {\n state.timedOut = true;\n onTimeout?.();\n reject(new Error(`Operation timed out after ${String(timeoutMs)}ms`));\n }, timeoutMs);\n });\n\n const promises: Array<Promise<T>> = [operation(), timeoutPromise];\n\n // Race against client AbortSignal if provided\n if (signal !== undefined && !signal.aborted) {\n const abortPromise = new Promise<never>((_resolve, reject) => {\n signal.addEventListener(\n 'abort',\n () => {\n reject(new Error('Operation cancelled by client'));\n },\n { once: true }\n );\n });\n promises.push(abortPromise);\n }\n\n return Promise.race(promises);\n }\n\n private handleSuccess<T>(\n result: T,\n startTime: number,\n timeoutMs: number,\n operationName: string\n ): Result<GuardedResult<T>, TimeoutError> {\n const durationMs = getTimeProvider().now() - startTime;\n const nearTimeout = durationMs > timeoutMs * NEAR_TIMEOUT_THRESHOLD;\n\n if (nearTimeout && this.enableLogging) {\n this.logger.warn('Operation completed near timeout threshold', {\n operation: operationName,\n durationMs,\n timeoutMs,\n thresholdPercent: Math.round((durationMs / timeoutMs) * 100),\n });\n }\n\n if (this.enableLogging) {\n this.logger.debug('Guarded operation completed', { operation: operationName, durationMs });\n }\n\n return ok({ value: result, durationMs, nearTimeout });\n }\n\n private handleFailure(\n timedOut: boolean,\n operationName: string,\n timeoutMs: number,\n startTime: number,\n cancelled = false\n ): TimeoutError {\n const durationMs = getTimeProvider().now() - startTime;\n\n if (cancelled) {\n this.logger.info('Operation cancelled by client', {\n operation: operationName,\n durationMs,\n });\n return {\n code: 'OPERATION_CANCELLED',\n message: `Operation '${operationName}' cancelled by client`,\n operation: operationName,\n };\n }\n\n if (timedOut) {\n this.logger.error('Operation timed out', undefined, {\n operation: operationName,\n timeoutMs,\n durationMs,\n });\n return createTimeoutError(operationName, timeoutMs);\n }\n\n return createGuardError(new Error('Unknown error'), operationName);\n }\n\n /**\n * Creates a guarded version of an async function.\n */\n guard<TArgs extends unknown[], TResult>(\n fn: (...args: TArgs) => Promise<TResult>,\n options?: { readonly timeoutMs?: number; readonly operationName?: string }\n ): (...args: TArgs) => Promise<Result<GuardedResult<TResult>, TimeoutError>> {\n return async (...args: TArgs): Promise<Result<GuardedResult<TResult>, TimeoutError>> => {\n return this.execute(() => fn(...args), options);\n };\n }\n}\n\n/**\n * URI validation utilities to complement timeout protection.\n */\nexport const UriValidation = {\n MAX_URI_LENGTH: 8192,\n MAX_TEMPLATE_DEPTH: 3,\n SUSPICIOUS_PATTERN: /\\{[+#./;?&]?[^}]*\\*\\}.*\\{[+#./;?&]?[^}]*\\*\\}|\\{(?:[^{}]*\\{){3,}/,\n\n validate(uri: string): Result<string, TimeoutError> {\n if (uri.length > this.MAX_URI_LENGTH) {\n return err({\n code: 'GUARD_ERROR',\n message: `URI exceeds maximum length: ${String(uri.length)} > ${String(this.MAX_URI_LENGTH)}`,\n operation: 'uri-validation',\n });\n }\n\n if (this.SUSPICIOUS_PATTERN.test(uri)) {\n return err({\n code: 'GUARD_ERROR',\n message: 'URI contains suspicious patterns that may cause performance issues',\n operation: 'uri-validation',\n });\n }\n\n return ok(uri);\n },\n\n sanitize(uri: string): string {\n const sanitized = uri.slice(0, this.MAX_URI_LENGTH);\n let depth = 0;\n let result = '';\n\n for (const char of sanitized) {\n if (char === '{') {\n depth++;\n if (depth > this.MAX_TEMPLATE_DEPTH) continue;\n } else if (char === '}') {\n if (depth > this.MAX_TEMPLATE_DEPTH) {\n depth--;\n continue;\n }\n depth--;\n }\n result += char;\n }\n\n return result;\n },\n};\n\n/**\n * Creates a timeout guard with default MCP-appropriate settings.\n */\nexport function createDefaultTimeoutGuard(logger?: ILogger): TimeoutGuard {\n const config: TimeoutGuardConfig = {\n defaultTimeoutMs: DEFAULT_TIMEOUT_MS,\n maxTimeoutMs: MAX_TIMEOUT_MS,\n enableLogging: true,\n };\n if (logger !== undefined) {\n return new TimeoutGuard({ ...config, logger });\n }\n return new TimeoutGuard(config);\n}\n","/**\n * Access Constraint Deriver — Unbypassable denylist (#1977 condition 3).\n *\n * Hardcoded patterns that no LLM-derived policy may override. Applied FIRST\n * in the enforcer, before checking the per-task policy. If the LLM (or a\n * malicious user objective) produces a policy that would allow access to\n * `.env`, SSH keys, cloud credentials, or similar, the denylist still wins.\n *\n * This exists because the LLM deriver is the weakest link — a user objective\n * that says \"I need to view my AWS credentials to debug\" would otherwise\n * produce a policy allowing `~/.aws/**`. The denylist refuses regardless.\n *\n * @module security/access-constraint-deriver/denylist\n */\n\n/**\n * File-path patterns that are unconditionally denied. Glob-style wildcards.\n * All matching is case-insensitive to catch `~/.SSH` and similar.\n */\nexport const UNBYPASSABLE_PATH_PATTERNS: readonly string[] = [\n // Environment files\n '.env',\n '.env.*',\n '**/.env',\n '**/.env.*',\n\n // SSH credentials\n '~/.ssh/**',\n '**/ssh/id_*',\n '**/*_rsa',\n '**/*_ed25519',\n '**/*.pem',\n\n // Cloud credentials\n '~/.aws/**',\n '~/.azure/**',\n '~/.gcp/**',\n '~/.config/gcloud/**',\n '~/.kube/config',\n\n // Unix secret files\n '/etc/shadow',\n '/etc/sudoers',\n '/etc/sudoers.d/**',\n\n // Common secret file patterns\n '**/secrets.*',\n '**/credentials.*',\n '**/private_key.*',\n '**/id_rsa*',\n];\n\n/**\n * Tool names that are unconditionally denied regardless of derived policy.\n * These are tools that should never be callable during automated agent\n * dispatch — they require explicit human action.\n */\nexport const UNBYPASSABLE_TOOL_NAMES: readonly string[] = [\n // Destructive git operations\n 'git_push_force',\n 'git_reset_hard',\n 'git_branch_delete_force',\n 'git_clean_force',\n\n // Destructive filesystem\n 'rm_recursive_force',\n 'chmod_recursive',\n\n // Identity / auth mutations\n 'ssh_add_key',\n 'gpg_add_key',\n 'npm_publish_force',\n\n // Remote destruction\n 'github_repo_delete',\n 'github_org_transfer',\n 'aws_account_close',\n];\n\n/**\n * Compiles a glob pattern to a regex at module-load time.\n * Supports: `**` (any path segments), `*` (any non-separator chars),\n * `~/` (home-anchor prefix). All other regex metachars escaped.\n *\n * Regexes built here come from the hardcoded `UNBYPASSABLE_PATH_PATTERNS`\n * constant — never from user input — so they are ReDoS-safe by construction.\n */\nfunction compileGlobToRegex(pattern: string): RegExp {\n const pat = pattern.toLowerCase();\n // Escape regex metacharacters INCLUDING backslash (per CodeQL — without\n // backslash in the class, a `\\` in input would leak into the regex output\n // unescaped). Do NOT escape `*` here — it's a glob wildcard that the\n // subsequent replaces expand into regex wildcards.\n const escaped = pat\n .replace(/[\\\\.+^$()|[\\]{}]/g, '\\\\$&')\n .replace(/\\*\\*/g, '__DOUBLESTAR__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DOUBLESTAR__/g, '.*');\n const anchored = escaped.startsWith('~/')\n ? `(^|/)${escaped.slice(2)}$`\n : escaped.startsWith('/')\n ? `^${escaped}$`\n : `(^|/)${escaped}$`;\n return new RegExp(anchored);\n}\n\n/**\n * Precompiled regexes for every unbypassable path pattern, computed once\n * at module load. Static inputs → no ReDoS surface.\n */\nconst COMPILED_PATH_PATTERNS: ReadonlyArray<{\n readonly pattern: string;\n readonly regex: RegExp;\n}> = UNBYPASSABLE_PATH_PATTERNS.map((pattern) => ({\n pattern,\n regex: compileGlobToRegex(pattern),\n}));\n\n/**\n * Returns true if a lowercased file path matches the given pattern.\n * Exported for tests; production code should use `isPathDenied`.\n */\nexport function matchDenyPattern(path: string, pattern: string): boolean {\n const normalized = path.toLowerCase();\n const compiled = COMPILED_PATH_PATTERNS.find((c) => c.pattern === pattern);\n if (compiled !== undefined) return compiled.regex.test(normalized);\n // Fallback for ad-hoc test patterns not in the static list.\n return compileGlobToRegex(pattern).test(normalized);\n}\n\n/** Returns true if the path hits any unbypassable pattern. */\nexport function isPathDenied(path: string): boolean {\n const normalized = path.toLowerCase();\n return COMPILED_PATH_PATTERNS.some((c) => c.regex.test(normalized));\n}\n\n/** Returns true if the tool name is unconditionally denied. */\nexport function isToolDenied(toolName: string): boolean {\n return UNBYPASSABLE_TOOL_NAMES.includes(toolName);\n}\n","/**\n * Tool risk classification for `confirm_risky` access-policy mode (#2279).\n *\n * Classifies each registered MCP tool as `read-only` (safe — log-and-allow\n * under confirm_risky) or `risky` (write/exec/network — block under\n * confirm_risky). Used by the policy enforcer to differentiate which\n * violations a human would have wanted to review.\n *\n * Classification policy:\n *\n * - **Read-only**: tool exclusively reads existing state — no file writes,\n * no subprocess execution, no network requests beyond a single bounded\n * read of project-internal data. `query_*`, `list_*`, `search_*`,\n * `*_query`, `*_analyze` patterns by default.\n * - **Risky**: tool writes files, runs subprocesses, posts to external\n * services, calls LLM APIs, or has any side effect that a human reviewer\n * would want to see before approving in confirm_risky mode.\n *\n * If a tool is unknown, it is treated as risky (default-deny) — same\n * principle as the unbypassable denylist: the security layer fails closed\n * on a misclassification.\n *\n * Update path: when adding a new MCP tool, classify it explicitly here.\n * The `inject-governance.ts check` CI gate ensures the registry list is\n * still the source of truth; this file is the risk overlay.\n *\n * @module security/access-constraint-deriver/tool-risk\n */\n\n/**\n * Tools that exclusively read state. Violations on these are log-and-allow\n * under `confirm_risky` mode — same as `audit` mode.\n */\nexport const READ_ONLY_TOOLS: ReadonlySet<string> = new Set([\n // Discovery / listing\n 'list_experts',\n 'list_workflows',\n // Research reads\n 'research_query',\n 'research_analyze',\n 'research_catalog_review',\n 'research_synthesize',\n // Memory reads\n 'memory_query',\n 'memory_stats',\n // Observability\n 'weather_report',\n 'query_trace',\n 'query_task_state',\n // Async-mode result polling (#3042 / epic #2631)\n 'get_job_result',\n // Async-mode job discovery (#3046 / epic #2631 Stage 5)\n 'list_jobs',\n // Codebase intelligence (read-only over local files)\n 'search_codebase',\n 'extract_symbols',\n // Repo analysis (read-only)\n 'repo_analyze',\n 'repo_security_plan',\n // Routing recommendation (no side effects — returns recommendation)\n 'delegate_to_model',\n // Registry import (returns a draft template — does not write)\n 'registry_import',\n]);\n\n/**\n * Returns true if the tool is risky under confirm_risky mode (default-deny\n * for unknown tools — security layer fails closed).\n */\nexport function isRiskyTool(toolName: string): boolean {\n return !READ_ONLY_TOOLS.has(toolName);\n}\n","/**\n * Access Constraint Deriver — Policy enforcement (#1977, #2279).\n *\n * Pure function that checks a proposed tool call against a derived policy\n * and returns an AccessDecision. Enforcement depends on the policy's mode:\n * - `off` and `audit` never block\n * - `confirm_risky` (#2279) blocks violations on risky tools (write/exec/\n * network) and log-and-allows violations on read-only tools\n * - `enforce` blocks every violation regardless of risk classification\n *\n * @module security/access-constraint-deriver/enforcer\n */\n\nimport { isPathDenied, isToolDenied } from './denylist.js';\nimport { isRiskyTool } from './tool-risk.js';\nimport type { AccessDecision, TaskAccessPolicy } from './types.js';\n\n/**\n * Checks a proposed tool call against the unbypassable denylist AND the\n * task's derived access policy.\n *\n * Order of operations (important — the denylist is FIRST and unbypassable):\n * 1. If the tool is on the hardcoded deny-tool list → deny regardless\n * of policy. This is unbypassable even in `off` mode.\n * 2. If a file-path argument is provided and matches an unbypassable path\n * pattern (e.g. `~/.ssh/**`, `/etc/shadow`) → deny regardless.\n * 3. Otherwise, fall back to the per-task policy (bypass in skeleton).\n *\n * The denylist check runs before the policy check so a malicious LLM-derived\n * policy cannot grant access to secrets/credentials by listing the tool in\n * `allowedTools`.\n */\nexport function checkAccess(\n toolName: string,\n policy: TaskAccessPolicy,\n args?: { readonly path?: string }\n): AccessDecision {\n // 1. Unbypassable tool denylist — applies in all modes.\n if (isToolDenied(toolName)) {\n return {\n decision: 'deny',\n reason: `tool \"${toolName}\" is on the unbypassable deny-tool list`,\n matchedRule: 'unbypassable:tool',\n };\n }\n\n // 2. Unbypassable path denylist — applies when a path argument is given.\n if (typeof args?.path === 'string' && args.path.length > 0 && isPathDenied(args.path)) {\n return {\n decision: 'deny',\n reason: `path \"${args.path}\" is on the unbypassable deny-path list`,\n matchedRule: 'unbypassable:path',\n };\n }\n\n // 3. Per-task policy check.\n if (policy.allowedTools === '*') return { decision: 'allow' };\n\n if (policy.allowedTools.includes(toolName)) return { decision: 'allow' };\n\n return decideOnViolation(toolName, policy.mode);\n}\n\n/**\n * Mode-specific behavior when a tool is not in the per-task allowlist.\n * Extracted so checkAccess stays under the complexity-10 cap.\n */\nfunction decideOnViolation(toolName: string, mode: TaskAccessPolicy['mode']): AccessDecision {\n if (mode === 'audit') {\n return {\n decision: 'log-and-allow',\n warning: `tool \"${toolName}\" not in derived policy (audit mode)`,\n };\n }\n // confirm_risky: split by tool risk classification (#2279). Read-only\n // violations are log-and-allow (audit-like); risky violations are denied\n // with a structured reason that surfaces \"would-have-required-approval\"\n // semantics. Operators add the tool to the allowlist after review, or\n // graduate to `enforce` once the violation rate is acceptable.\n if (mode === 'confirm_risky') {\n if (!isRiskyTool(toolName)) {\n return {\n decision: 'log-and-allow',\n warning: `tool \"${toolName}\" not in derived policy (confirm_risky mode, read-only — would have required human approval, allowed because read-only)`,\n };\n }\n return {\n decision: 'deny',\n reason: `tool \"${toolName}\" not in derived policy (confirm_risky mode, risky — would have required human approval; denied for now, add to allowedTools or run in audit mode to allow)`,\n matchedRule: 'allowedTools:confirm_risky',\n };\n }\n return {\n decision: 'deny',\n reason: `tool \"${toolName}\" not in derived policy`,\n matchedRule: 'allowedTools',\n };\n}\n","/**\n * Access Constraint Deriver — MCP tool dispatch guard (#1977 final wiring).\n *\n * Per-call helper and middleware factory that plugs the access-constraint\n * enforcer into the MCP tool dispatch path. Runs AFTER policy derivation\n * (deriver.ts owns that) and BEFORE the tool handler executes.\n *\n * Behavior matrix:\n * - mode=off → no-op, allows every call (this is the default; runtime\n * behavior is unchanged from pre-#1977)\n * - mode=audit → checks against the policy; on violation, logs a warning\n * and still forwards to the handler\n * - mode=enforce → checks against the policy; on violation, returns an\n * MCP-format isError result without invoking the handler\n *\n * The enforcer's hardcoded denylist (denylist.ts) runs FIRST regardless\n * of mode. Even `off` mode denies destructive tools and secret paths.\n *\n * @module security/access-constraint-deriver/mcp-guard\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { checkAccess } from './enforcer.js';\nimport type { AccessDecision, TaskAccessPolicy } from './types.js';\n\n/** AsyncLocalStorage holding the active task's access policy. */\nconst accessPolicyStorage = new AsyncLocalStorage<TaskAccessPolicy>();\n\n/**\n * Run `fn` with `policy` available to any nested MCP tool dispatch.\n *\n * Orchestrators (orchestrate, execute_expert, etc.) derive a policy at\n * task start and wrap downstream work in this helper. Tool handlers that\n * use `guardMcpToolCall` will read the policy from ALS.\n */\nexport function withAccessPolicy<T>(policy: TaskAccessPolicy, fn: () => Promise<T>): Promise<T> {\n return accessPolicyStorage.run(policy, fn);\n}\n\n/**\n * Returns the active access policy, or undefined if no wrapping `withAccessPolicy`\n * is in scope. When undefined, `guardMcpToolCall` treats the request as\n * mode=off (permissive) since no task context has been established.\n */\nexport function getActivePolicy(): TaskAccessPolicy | undefined {\n return accessPolicyStorage.getStore();\n}\n\n/**\n * Input-hints a tool handler can surface so the guard can reason about\n * file-path arguments. Tools with a `path` arg should pass it; tools\n * without can omit.\n */\nexport interface GuardArgs {\n readonly path?: string;\n}\n\n/**\n * Check a proposed MCP tool call against the active access policy.\n *\n * Pure function — does not mutate the policy or the storage. Returns an\n * AccessDecision the caller interprets:\n *\n * - `allow`: invoke the handler\n * - `deny`: do not invoke; return a RefuseAction / isError result upstream\n * - `log-and-allow`: log a warning, then invoke the handler (audit mode)\n *\n * When no policy is in ALS (no wrapping `withAccessPolicy`), this returns\n * `allow` — the guard is opt-in at the orchestrator layer.\n */\nexport function guardMcpToolCall(toolName: string, args?: GuardArgs): AccessDecision {\n const policy = getActivePolicy();\n if (policy === undefined) return { decision: 'allow' };\n return checkAccess(toolName, policy, args);\n}\n\n/**\n * Shape of the logger the middleware uses. Minimal to avoid coupling.\n */\ninterface MiddlewareLogger {\n warn: (message: string, context?: Record<string, unknown>) => void;\n info: (message: string, context?: Record<string, unknown>) => void;\n}\n\n/**\n * Formats a deny decision as an MCP-compliant isError ToolResult shape.\n * The MCP server's middleware chain recognizes `{ isError, content }` and\n * surfaces it as a tool error to the caller.\n */\nexport function denyToToolResult(\n decision: Extract<AccessDecision, { decision: 'deny' }>,\n requestId: string\n): { isError: true; content: Array<{ type: 'text'; text: string }> } {\n return {\n isError: true,\n content: [\n {\n type: 'text',\n text: `access denied: ${decision.reason} (rule: ${decision.matchedRule}, request: ${requestId})`,\n },\n ],\n };\n}\n\n/**\n * Create an access-policy middleware that plugs into the MCP middleware\n * chain. Reads the active policy from ALS. When no policy is active OR\n * the policy is in `off` mode, this middleware is a no-op pass-through.\n */\nexport function createAccessPolicyMiddleware(config: {\n readonly toolName: string;\n readonly logger: MiddlewareLogger;\n}): (\n args: unknown,\n ctx: { readonly requestContext: { readonly requestId: string } },\n next: (args: unknown, ctx: unknown) => Promise<unknown>\n) => Promise<unknown> {\n return async (args, ctx, next) => {\n const policy = getActivePolicy();\n if (policy === undefined || policy.mode === 'off') {\n return next(args, ctx);\n }\n\n const guardArgs = toGuardArgs(args);\n const decision = checkAccess(config.toolName, policy, guardArgs);\n\n if (decision.decision === 'allow') {\n return next(args, ctx);\n }\n if (decision.decision === 'log-and-allow') {\n config.logger.warn('access-policy: audit violation', {\n tool: config.toolName,\n warning: decision.warning,\n policySource: policy.source,\n requestId: ctx.requestContext.requestId,\n });\n return next(args, ctx);\n }\n // decision.decision === 'deny'\n config.logger.info('access-policy: tool call denied', {\n tool: config.toolName,\n reason: decision.reason,\n matchedRule: decision.matchedRule,\n policySource: policy.source,\n mode: policy.mode,\n requestId: ctx.requestContext.requestId,\n });\n return denyToToolResult(decision, ctx.requestContext.requestId);\n };\n}\n\n/** Extract path from a typed tool-arg record, if present and a string. */\nfunction toGuardArgs(args: unknown): GuardArgs | undefined {\n if (typeof args !== 'object' || args === null) return undefined;\n const path = (args as Record<string, unknown>)['path'];\n return typeof path === 'string' && path.length > 0 ? { path } : undefined;\n}\n","/**\n * Access Constraint Deriver — MCP middleware-chain adapter (#1977 activation).\n *\n * Bridges `createAccessPolicyMiddleware` (which returns a generic\n * `Promise<unknown>`-shaped middleware) to the strongly-typed `Middleware`\n * contract used by `mcp/middleware/middleware-chain.ts`.\n *\n * Mounted into the standard middleware stack so every tool call passes\n * through the ClawGuard enforcer. When no orchestrator has wrapped the\n * call with `withAccessPolicy(...)`, this adapter is a no-op pass-through\n * — runtime behavior is unchanged for callers that don't set up a policy.\n *\n * @module security/access-constraint-deriver/chain-adapter\n */\n\nimport { checkAccess } from './enforcer.js';\nimport { denyToToolResult, getActivePolicy } from './mcp-guard.js';\nimport type { GuardArgs } from './mcp-guard.js';\n// Type-only import: no runtime cycle with mcp/middleware/middleware-chain.ts.\nimport type { Middleware } from '../../mcp/middleware/middleware-chain.js';\n\nfunction toGuardArgs(args: unknown): GuardArgs | undefined {\n if (typeof args !== 'object' || args === null) return undefined;\n const path = (args as Record<string, unknown>)['path'];\n return typeof path === 'string' && path.length > 0 ? { path } : undefined;\n}\n\n/**\n * Builds a middleware-chain-compatible access-policy middleware for\n * `toolName`. Reads the active `TaskAccessPolicy` from `AsyncLocalStorage`\n * (populated by `withAccessPolicy`). When no policy is active OR the\n * policy is in `off` mode, the middleware is a no-op pass-through.\n */\nexport function createAccessPolicyChainMiddleware(toolName: string): Middleware {\n return async (args, ctx, next) => {\n const policy = getActivePolicy();\n if (policy === undefined || policy.mode === 'off') {\n return next(args, ctx);\n }\n\n const decision = checkAccess(toolName, policy, toGuardArgs(args));\n\n if (decision.decision === 'allow') {\n return next(args, ctx);\n }\n if (decision.decision === 'log-and-allow') {\n ctx.logger.warn('access-policy: audit violation', {\n tool: toolName,\n warning: decision.warning,\n policySource: policy.source,\n requestId: ctx.requestContext.requestId,\n });\n return next(args, ctx);\n }\n ctx.logger.info('access-policy: tool call denied', {\n tool: toolName,\n reason: decision.reason,\n matchedRule: decision.matchedRule,\n policySource: policy.source,\n mode: policy.mode,\n requestId: ctx.requestContext.requestId,\n });\n return denyToToolResult(decision, ctx.requestContext.requestId);\n };\n}\n","/**\n * nexus-agents/mcp - Centralized Middleware Chain\n *\n * Provides a composable middleware chain for MCP tools with guaranteed\n * execution order: auth → validation → policy → rate-limit → timeout → audit\n *\n * @module mcp/middleware/middleware-chain\n * (Source: Issue #189 - Centralized MCP middleware chain)\n */\n\nimport type { z } from 'zod';\nimport type { ILogger } from '../../core/index.js';\nimport { createLogger, getTimeProvider } from '../../core/index.js';\nimport { validateToolInput } from './validation.js';\nimport { RateLimiter, type RateLimiterConfig } from './rate-limiter.js';\nimport { type IPolicyFirewall, type ExecutionMode, createPolicyContext } from './policy.js';\nimport { TimeoutGuard, type TimeoutGuardConfig } from './timeout-guard.js';\nimport { MCP_TIMEOUTS } from '../../config/timeouts.js';\nimport { createRequestContext, contextForLogging, type RequestContext } from './request-context.js';\nimport { createMetricsMiddleware } from './tool-metrics.js';\nimport { abortSignalStorage } from '../mcp-notifier.js';\nimport { createAccessPolicyChainMiddleware } from '../../security/access-constraint-deriver/chain-adapter.js';\nimport { toolStructuredError } from '../tools/tool-result.js';\nimport type { ErrorCategory } from '../error-envelope.js';\n\n/**\n * MCP tool result type.\n *\n * This interface is structurally compatible with the MCP SDK's CallToolResult.\n * The content array accepts text content for simplicity, while remaining\n * compatible with the SDK's broader ContentBlock type at runtime.\n */\nexport interface ToolResult {\n /** Content blocks returned by the tool (text content) */\n content: Array<{ type: 'text'; text: string }>;\n /** Whether this represents an error result */\n isError?: boolean;\n /** Structured output for SDK outputSchema validation (Issue #1117) */\n structuredContent?: Record<string, unknown>;\n /** Out-of-band metadata — carries the #2649 error envelope on errors. */\n _meta?: Record<string, unknown>;\n}\n\n/**\n * Middleware context passed through the chain.\n */\nexport interface MiddlewareContext {\n /** Unique request ID for tracing */\n readonly requestContext: RequestContext;\n /** Logger with request context */\n readonly logger: ILogger;\n /** Validated arguments (set after validation middleware) */\n validatedArgs?: unknown;\n}\n\n/**\n * Middleware function signature.\n * Each middleware receives the context and a next function to call.\n */\nexport type Middleware = (\n args: unknown,\n ctx: MiddlewareContext,\n next: (args: unknown, ctx: MiddlewareContext) => Promise<ToolResult>\n) => Promise<ToolResult>;\n\n/**\n * Configuration for the middleware chain.\n */\nexport interface MiddlewareChainConfig {\n /** Tool name for logging and policy evaluation */\n toolName: string;\n /** Zod schema for input validation (optional) */\n schema?: z.ZodType;\n /** Policy firewall instance (optional) */\n policyFirewall?: IPolicyFirewall | undefined;\n /** Execution mode for policy evaluation */\n executionMode?: ExecutionMode | undefined;\n /** Allowed paths for file operations */\n allowedPaths?: readonly string[] | undefined;\n /** Rate limiter configuration (optional) */\n rateLimiter?: RateLimiterConfig | RateLimiter | undefined;\n /** Timeout configuration (optional) */\n timeout?: TimeoutGuardConfig | undefined;\n /** Logger instance (optional) */\n logger?: ILogger | undefined;\n /** Skip specific middleware steps */\n skip?: MiddlewareSkipConfig | undefined;\n}\n\n/**\n * Configuration for skipping middleware steps.\n */\nexport interface MiddlewareSkipConfig {\n validation?: boolean | undefined;\n policy?: boolean | undefined;\n rateLimit?: boolean | undefined;\n timeout?: boolean | undefined;\n audit?: boolean | undefined;\n /** Skip the ClawGuard access-policy middleware (#1977). */\n accessPolicy?: boolean | undefined;\n}\n\n/**\n * Tool handler function signature.\n */\nexport type ToolHandler = (args: unknown) => Promise<ToolResult>;\n\n/**\n * Context-aware handler that receives middleware context.\n */\nexport type ContextAwareToolHandler = (\n args: unknown,\n ctx: MiddlewareContext\n) => Promise<ToolResult>;\n\n/**\n * Creates an error result with the structured error envelope (#2649).\n * Each middleware passes the category that matches its failure mode.\n */\nfunction errorResult(category: ErrorCategory, message: string, requestId: string): ToolResult {\n return toolStructuredError({\n errorCategory: category,\n message: `${message} (request: ${requestId})`,\n });\n}\n\n/**\n * Creates validation middleware.\n */\nfunction createValidationMiddleware(schema: z.ZodType): Middleware {\n return async (args, ctx, next) => {\n const result = validateToolInput(schema, args);\n if (!result.ok) {\n ctx.logger.warn('Validation failed', {\n error: result.error.message,\n });\n return errorResult(\n 'validation',\n `Validation error: ${result.error.message}`,\n ctx.requestContext.requestId\n );\n }\n ctx.validatedArgs = result.value;\n return next(result.value, ctx);\n };\n}\n\n/**\n * Creates policy middleware.\n */\nfunction createPolicyMiddleware(\n firewall: IPolicyFirewall,\n toolName: string,\n mode: ExecutionMode,\n allowedPaths?: readonly string[]\n): Middleware {\n return async (args, ctx, next) => {\n const policyCtx = createPolicyContext(toolName, args, {\n mode,\n ...(allowedPaths !== undefined && { allowedPaths }),\n });\n const decision = firewall.evaluate(policyCtx);\n\n if (!decision.allowed) {\n ctx.logger.warn('Policy denied', {\n reason: decision.reason,\n ruleName: decision.ruleName,\n });\n return errorResult(\n 'permission',\n `Policy denied: ${decision.reason}`,\n ctx.requestContext.requestId\n );\n }\n ctx.logger.debug('Policy check passed', { reason: decision.reason });\n return next(args, ctx);\n };\n}\n\n/**\n * Creates rate limit middleware.\n */\nfunction createRateLimitMiddleware(limiter: RateLimiter): Middleware {\n return async (args, ctx, next) => {\n const acquired = limiter.tryAcquire();\n if (!acquired) {\n const state = limiter.getState();\n ctx.logger.warn('Rate limit exceeded', {\n nextTokenMs: state.nextTokenMs,\n });\n return errorResult(\n 'transient',\n `Rate limit exceeded. Try again in ${String(state.nextTokenMs)}ms`,\n ctx.requestContext.requestId\n );\n }\n return next(args, ctx);\n };\n}\n\n/**\n * Creates timeout middleware.\n * Reads AbortSignal from AsyncLocalStorage for client cancellation support.\n */\nfunction createTimeoutMiddleware(guard: TimeoutGuard, toolName: string): Middleware {\n return async (args, ctx, next) => {\n const signal = abortSignalStorage.getStore();\n const result = await guard.execute(() => next(args, ctx), {\n operationName: toolName,\n ...(signal !== undefined ? { signal } : {}),\n });\n\n if (!result.ok) {\n ctx.logger.error('Operation timed out', undefined, {\n code: result.error.code,\n timeoutMs: result.error.timeoutMs,\n });\n // #3726 discoverability: append the per-tool hint (e.g. \"retry in async\n // job-mode\") so a sync long-running tool that hits its ceiling tells the\n // caller how to escape it. Absent hint → message unchanged.\n const hint = MCP_TIMEOUTS.perToolTimeoutHint[toolName];\n const message = hint !== undefined ? `${result.error.message} ${hint}` : result.error.message;\n // Timeout — transient, a retry with more headroom may succeed.\n return errorResult('transient', message, ctx.requestContext.requestId);\n }\n\n if (result.value.nearTimeout) {\n ctx.logger.warn('Operation completed near timeout threshold', {\n durationMs: result.value.durationMs,\n });\n }\n\n return result.value.value;\n };\n}\n\n/**\n * Creates audit middleware that logs start/end of request.\n */\nfunction createAuditMiddleware(): Middleware {\n return async (args, ctx, next) => {\n const startTime = getTimeProvider().now();\n ctx.logger.info('Tool invocation started');\n\n try {\n const result = await next(args, ctx);\n const durationMs = getTimeProvider().now() - startTime;\n\n if (result.isError === true) {\n ctx.logger.warn('Tool execution completed with error', { durationMs });\n } else {\n ctx.logger.info('Tool execution completed', { durationMs });\n }\n return result;\n } catch (error) {\n const durationMs = getTimeProvider().now() - startTime;\n const message = error instanceof Error ? error.message : 'Unknown error';\n ctx.logger.error('Tool execution failed', error instanceof Error ? error : undefined, {\n durationMs,\n });\n return errorResult('internal', `Internal error: ${message}`, ctx.requestContext.requestId);\n }\n };\n}\n\n/**\n * Composes multiple middleware functions into a single chain.\n */\nfunction composeMiddleware(middlewares: Middleware[]): Middleware {\n return (args, ctx, finalHandler) => {\n const dispatch = (index: number, currentArgs: unknown): Promise<ToolResult> => {\n if (index >= middlewares.length) {\n return finalHandler(currentArgs, ctx);\n }\n const middleware = middlewares[index];\n if (middleware === undefined) {\n return finalHandler(currentArgs, ctx);\n }\n return middleware(currentArgs, ctx, (nextArgs) => dispatch(index + 1, nextArgs));\n };\n return dispatch(0, args);\n };\n}\n\n/** Helper: adds audit middleware if not skipped */\nfunction addAuditMiddleware(middlewares: Middleware[], skip: MiddlewareSkipConfig): void {\n if (skip.audit !== true) {\n middlewares.push(createAuditMiddleware());\n }\n}\n\n/** Helper: adds rate limit middleware if configured */\nfunction addRateLimitMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.rateLimit !== true && config.rateLimiter !== undefined) {\n const limiter =\n config.rateLimiter instanceof RateLimiter\n ? config.rateLimiter\n : new RateLimiter(config.rateLimiter);\n middlewares.push(createRateLimitMiddleware(limiter));\n }\n}\n\n/** Helper: adds validation middleware if schema provided */\nfunction addValidationMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.validation !== true && config.schema !== undefined) {\n middlewares.push(createValidationMiddleware(config.schema));\n }\n}\n\n/** Helper: adds policy middleware if configured */\nfunction addPolicyMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.policy !== true && config.policyFirewall !== undefined) {\n const mode = config.executionMode ?? 'read-only';\n middlewares.push(\n createPolicyMiddleware(config.policyFirewall, config.toolName, mode, config.allowedPaths)\n );\n }\n}\n\n/** Helper: adds timeout middleware if configured */\nfunction addTimeoutMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.timeout !== true && config.timeout !== undefined) {\n const guard = new TimeoutGuard(config.timeout);\n middlewares.push(createTimeoutMiddleware(guard, config.toolName));\n }\n}\n\n/**\n * Helper: adds the ClawGuard access-policy middleware (#1977).\n *\n * Always added unless explicitly skipped. The middleware is ALS-backed\n * and a no-op pass-through when no orchestrator has called\n * `withAccessPolicy(...)` — so runtime behavior is unchanged for callers\n * that haven't opted in.\n */\nfunction addAccessPolicyMiddleware(\n middlewares: Middleware[],\n config: MiddlewareChainConfig,\n skip: MiddlewareSkipConfig\n): void {\n if (skip.accessPolicy !== true) {\n middlewares.push(createAccessPolicyChainMiddleware(config.toolName));\n }\n}\n\n/** Helper: builds the middleware stack */\nfunction buildMiddlewareStack(config: MiddlewareChainConfig): Middleware[] {\n const skip = config.skip ?? {};\n const middlewares: Middleware[] = [];\n\n middlewares.push(createMetricsMiddleware()); // Tool usage analytics (#1022)\n addAuditMiddleware(middlewares, skip);\n addRateLimitMiddleware(middlewares, config, skip);\n addValidationMiddleware(middlewares, config, skip);\n addPolicyMiddleware(middlewares, config, skip);\n addAccessPolicyMiddleware(middlewares, config, skip); // #1977 ClawGuard\n addTimeoutMiddleware(middlewares, config, skip);\n\n return middlewares;\n}\n\n/**\n * Creates a middleware chain with the standard execution order.\n *\n * Order: audit → rate-limit → validation → policy → timeout → handler\n *\n * Audit wraps everything to capture timing. Rate limit is checked early\n * to reject requests before expensive validation. Timeout wraps the\n * actual handler execution.\n *\n * @param config - Chain configuration\n * @returns A function that wraps handlers with the middleware chain\n */\nexport function createMiddlewareChain(\n config: MiddlewareChainConfig\n): (handler: ContextAwareToolHandler) => ToolHandler {\n const logger = config.logger ?? createLogger({ tool: config.toolName });\n const middlewares = buildMiddlewareStack(config);\n const composed = composeMiddleware(middlewares);\n\n return (handler: ContextAwareToolHandler): ToolHandler => {\n return async (args: unknown): Promise<ToolResult> => {\n const requestContext = createRequestContext({ toolName: config.toolName });\n const requestLogger = logger.child(contextForLogging(requestContext));\n const ctx: MiddlewareContext = { requestContext, logger: requestLogger };\n return composed(args, ctx, (finalArgs, finalCtx) => handler(finalArgs, finalCtx));\n };\n };\n}\n\n/**\n * Convenience function to wrap a handler with default middleware.\n *\n * @param toolName - Name of the tool\n * @param handler - The tool handler\n * @param options - Optional middleware configuration\n * @returns Wrapped handler with middleware\n */\nexport function withMiddleware(\n toolName: string,\n handler: ContextAwareToolHandler | ToolHandler,\n options?: Partial<Omit<MiddlewareChainConfig, 'toolName'>>\n): ToolHandler {\n // Note: Policy firewall is NOT added by default - must be explicitly configured\n // This follows the principle of minimal defaults with explicit opt-in for security\n const config: MiddlewareChainConfig = {\n toolName,\n ...options,\n };\n\n const chain = createMiddlewareChain(config);\n\n // Wrap handler to support both signatures\n const wrappedHandler: ContextAwareToolHandler = (args, ctx) => {\n // Check if handler expects context (2 params)\n if (handler.length >= 2) {\n return handler(args, ctx);\n }\n return (handler as ToolHandler)(args);\n };\n\n return chain(wrappedHandler);\n}\n\n/**\n * Creates a middleware chain factory with shared configuration.\n *\n * @param sharedConfig - Configuration shared across all tools\n * @returns Factory function for creating wrapped handlers\n */\nexport function createMiddlewareFactory(\n sharedConfig: Omit<MiddlewareChainConfig, 'toolName' | 'schema'>\n): (\n toolName: string,\n handler: ContextAwareToolHandler | ToolHandler,\n schema?: z.ZodType\n) => ToolHandler {\n return (toolName, handler, schema) => {\n const options = schema !== undefined ? { ...sharedConfig, schema } : sharedConfig;\n return withMiddleware(toolName, handler, options);\n };\n}\n","/**\n * MCP Tool Annotations Registry — DERIVED VIEW (#993; folded into the manifest #3597).\n *\n * The per-tool annotation + side-effect DATA now lives in the canonical\n * {@link TOOL_MANIFEST} (one `{ name, annotations, sideEffects }` entry per tool,\n * #3597 increment 2 of #3563). This module is the keyed-record + accessor view\n * over that data: `TOOL_ANNOTATIONS` is derived from the manifest (each entry's\n * `.annotations`/`.sideEffects` are the SAME objects the manifest holds — no\n * clone, so reference identity is preserved for the live accessor in\n * `mcp/tool-annotations.ts`). The annotation TYPES are defined in the manifest\n * (the import-free leaf) and re-exported here for the existing consumers.\n *\n * @module mcp/tools/tool-annotations\n * (Source: Issue #993 — Document MCP tool side effects in schema metadata)\n */\n\nimport {\n TOOL_MANIFEST,\n type SideEffectCategory,\n type SideEffect,\n type ToolAnnotations,\n type ToolSideEffectsEntry,\n} from './tool-manifest.js';\n\n// Re-export the annotation types from their canonical home (the manifest leaf)\n// so existing consumers can keep importing them from this module.\nexport type { SideEffectCategory, SideEffect, ToolAnnotations, ToolSideEffectsEntry };\n\n/**\n * Canonical registry of tool annotations and side effects, keyed by tool name.\n * Derived from {@link TOOL_MANIFEST}; each value's `annotations`/`sideEffects`\n * reference the manifest entry's own objects (preserving identity).\n */\nexport const TOOL_ANNOTATIONS: Readonly<Record<string, ToolSideEffectsEntry>> = Object.freeze(\n Object.fromEntries(\n TOOL_MANIFEST.map((entry) => [\n entry.name,\n { annotations: entry.annotations, sideEffects: entry.sideEffects },\n ])\n )\n);\n\n/**\n * Returns the annotations for a given tool, or undefined if not found.\n */\nexport function getToolAnnotations(toolName: string): ToolSideEffectsEntry | undefined {\n return TOOL_ANNOTATIONS[toolName];\n}\n\n/**\n * Returns only the MCP protocol annotations for a tool (for registerTool config).\n */\nexport function getMcpAnnotations(toolName: string): ToolAnnotations | undefined {\n return TOOL_ANNOTATIONS[toolName]?.annotations;\n}\n\n/**\n * Returns side effects for a tool filtered by category.\n */\nexport function getSideEffectsByCategory(\n toolName: string,\n category: SideEffectCategory\n): readonly SideEffect[] {\n const entry = TOOL_ANNOTATIONS[toolName];\n if (entry === undefined) return [];\n return entry.sideEffects.filter((se) => se.category === category);\n}\n","/**\n * Central per-tool MCP annotations accessors (#2648, Epic A; consolidated #3358).\n *\n * The MCP 2025-11-25 spec defines four boolean hints clients use to reason\n * about each tool's safety, retry semantics, and permission UX:\n *\n * - `readOnlyHint` — tool does not modify persistent state\n * - `destructiveHint` — tool can perform destructive operations\n * - `idempotentHint` — calling with the same input is safe to repeat\n * - `openWorldHint` — tool interacts with systems outside the server's control\n *\n * Per the MCP spec these are **hints**, not enforcement primitives — clients\n * should never trust them from an untrusted server. But for nexus-agents (a\n * governance substrate) the hints are load-bearing for:\n *\n * - Programmatic prerequisite gates (Epic B / #2652) — uses\n * `destructiveHint` and `openWorldHint` to decide what to gate.\n * - Retry policy decisions in pipeline runners — only retry tools where\n * `idempotentHint === true`.\n * - Permission-prompt UX consistency across Claude / Codex / Gemini /\n * OpenCode harnesses.\n *\n * The audit (#2648 / docs/research/nexus-agents-multi-harness-alignment-audit.md\n * §6 T14) requires **every** registered tool declare all four hints\n * explicitly — no defaults.\n *\n * **Single source of truth (#3358):** the per-tool annotation DATA lives in\n * the side-effects superset registry at `./tools/tool-annotations.ts`, where\n * each entry pairs the MCP hints (`.annotations`) with curated side-effects\n * metadata (#993). This file is the LIVE ACCESSOR path: each tool's\n * `registerTool()` call site reads its annotations via `getToolAnnotations(name)`.\n * Data flows data-file → accessor-file only (no circular import).\n *\n * @module mcp/tool-annotations\n */\n\nimport type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { TOOL_ANNOTATIONS as TOOL_SIDE_EFFECTS } from './tools/tool-annotations.js';\n\n/**\n * Look up the MCP annotations for a registered MCP tool. Throws if the tool\n * name isn't in the central registry — this enforces \"every tool declares its\n * hints explicitly\" rather than silently falling back to MCP's defaults\n * (which assume destructive + non-idempotent + open-world).\n *\n * The data is derived from the side-effects superset registry\n * (`./tools/tool-annotations.ts`, #993); only the four MCP hint booleans are\n * returned here — side-effects metadata is reached via that module's\n * `getSideEffectsByCategory`.\n */\nexport function getToolAnnotations(name: string): ToolAnnotations {\n const entry = TOOL_SIDE_EFFECTS[name];\n if (entry === undefined) {\n throw new Error(\n `getToolAnnotations: no entry for tool \"${name}\". Add it to TOOL_ANNOTATIONS in src/mcp/tools/tool-annotations.ts (#2648/#3358).`\n );\n }\n return entry.annotations;\n}\n","/**\n * nexus-agents/consensus - Core Type Definitions\n *\n * Core type definitions and Zod schemas for the consensus engine.\n * Supports multiple voting strategies for multi-agent decisions.\n */\n\nimport { z } from 'zod';\n\n/**\n * Consensus algorithm types.\n * - simple_majority: >50% of votes required\n * - supermajority: >=67% of votes required\n * - unanimous: 100% approval required\n * - proof_of_learning: weighted voting based on agent performance\n * - opinion_wise: higher-order voting with correlation awareness (Issue #333)\n * - higher_order: alias for opinion_wise (Issue #514)\n */\nexport const ConsensusAlgorithmSchema = z.enum([\n 'simple_majority',\n 'supermajority',\n 'unanimous',\n 'proof_of_learning',\n 'opinion_wise',\n 'higher_order',\n]);\nexport type ConsensusAlgorithm = z.infer<typeof ConsensusAlgorithmSchema>;\n\n/**\n * Vote decision options.\n */\nexport const VoteDecisionSchema = z.enum(['approve', 'reject', 'abstain']);\nexport type VoteDecision = z.infer<typeof VoteDecisionSchema>;\n\n/**\n * Proposal status in the lifecycle.\n */\nexport const ProposalStatusSchema = z.enum([\n 'pending',\n 'voting',\n 'approved',\n 'rejected',\n 'timeout',\n 'closed',\n]);\nexport type ProposalStatus = z.infer<typeof ProposalStatusSchema>;\n\n/**\n * Structured rejection feedback categories (Issue #1213).\n * Enables reject→refine→re-vote feedback loops by classifying rejection reasons.\n */\nexport const RejectionCategorySchema = z.enum([\n 'YAGNI',\n 'DRY_VIOLATION',\n 'OVER_ENGINEERING',\n 'SCOPE_CREEP',\n 'SECURITY_RISK',\n 'MISALIGNED',\n 'INSUFFICIENT_EVIDENCE',\n]);\nexport type RejectionCategory = z.infer<typeof RejectionCategorySchema>;\n\n/**\n * All valid rejection category values, for runtime reference.\n */\nexport const REJECTION_CATEGORIES = RejectionCategorySchema.options;\n\n/**\n * Pre-verified finding emitted by a voter (#2245 v4 follow-up).\n * Mirrors `cli/voter-response.ts:RawFindingSchema` — kept inline here to\n * avoid a circular cli→consensus import. Downstream code in mcp/tools\n * adds the derived `verified` flag based on the gate fields.\n */\nconst FindingShapeSchema = z.object({\n summary: z.string().min(1).max(500),\n location: z.string().min(1).max(200),\n severity: z.enum(['critical', 'high', 'medium', 'low']).default('medium'),\n gate: z.object({\n reread_cited_line: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n traced_call_path: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n named_assertion: z.string().default(''),\n ruled_out_language_non_issue: z.enum(['passed', 'failed', 'skipped']).default('skipped'),\n }),\n claim: z.string().min(1).max(2000),\n});\n\n/**\n * A vote cast by an agent.\n */\nexport const VoteSchema = z.object({\n decision: VoteDecisionSchema,\n reasoning: z.string().min(1).describe('Explanation for the vote'),\n confidence: z.number().min(0).max(1).describe('Confidence level 0-1'),\n conditions: z.array(z.string()).optional().describe('Conditions for approval'),\n /** Structured rejection categories for reject→refine→re-vote loops (Issue #1213). */\n rejectionCategories: z\n .array(RejectionCategorySchema)\n .optional()\n .describe('Rejection reason categories when decision is reject'),\n /** Pre-verified PR-review findings (#2245 v4 follow-up). Optional;\n * populated only when the voter emits the structured top-level array. */\n findings: z.array(FindingShapeSchema).optional().describe('PR-review findings (pre-verified)'),\n timestamp: z.iso.datetime().optional(),\n});\nexport type Vote = z.infer<typeof VoteSchema>;\n\n/**\n * A proposal submitted for consensus.\n */\nexport const ProposalSchema = z.object({\n id: z.string().optional().describe('Auto-generated if not provided'),\n title: z.string().min(1).max(200).describe('Short proposal title'),\n description: z.string().min(1).describe('Detailed proposal description'),\n algorithm: ConsensusAlgorithmSchema,\n timeout: z.number().int().positive().optional().describe('Timeout in milliseconds'),\n requiredVoters: z.array(z.string()).optional().describe('Agent IDs that must vote'),\n metadata: z.record(z.string(), z.unknown()).optional().describe('Additional context'),\n createdAt: z.iso.datetime().optional(),\n});\nexport type Proposal = z.infer<typeof ProposalSchema>;\n\n/**\n * Unique identifier for a proposal.\n */\nexport type ProposalId = string;\n\n/**\n * Vote counts summary.\n */\nexport interface VoteCounts {\n approve: number;\n reject: number;\n abstain: number;\n total: number;\n}\n\n/**\n * Weighted vote counts for proof-of-learning.\n */\nexport interface WeightedVoteCounts {\n approve: number;\n reject: number;\n abstain: number;\n totalWeight: number;\n}\n\n/**\n * Result of a consensus decision.\n */\nexport interface ConsensusResult {\n proposalId: ProposalId;\n proposal: Proposal;\n outcome: ProposalStatus;\n votes: Map<string, Vote>;\n voteCounts: VoteCounts;\n weightedCounts?: WeightedVoteCounts | undefined;\n approvalPercentage: number;\n quorumReached: boolean;\n startedAt: string;\n closedAt: string;\n durationMs: number;\n}\n\n/**\n * Consensus result schema for validation.\n */\nexport const ConsensusResultSchema = z.object({\n proposalId: z.string(),\n proposal: ProposalSchema,\n outcome: ProposalStatusSchema,\n votes: z.map(z.string(), VoteSchema),\n voteCounts: z.object({\n approve: z.number().int().nonnegative(),\n reject: z.number().int().nonnegative(),\n abstain: z.number().int().nonnegative(),\n total: z.number().int().nonnegative(),\n }),\n weightedCounts: z\n .object({\n approve: z.number().nonnegative(),\n reject: z.number().nonnegative(),\n abstain: z.number().nonnegative(),\n totalWeight: z.number().nonnegative(),\n })\n .optional(),\n approvalPercentage: z.number().min(0).max(100),\n quorumReached: z.boolean(),\n startedAt: z.iso.datetime(),\n closedAt: z.iso.datetime(),\n durationMs: z.number().int().nonnegative(),\n});\n\n/**\n * Agent performance record for proof-of-learning.\n */\nexport interface AgentPerformance {\n agentId: string;\n totalVotes: number;\n correctVotes: number;\n successRate: number;\n lastUpdated: string;\n}\n\n/**\n * Agent performance schema.\n */\nexport const AgentPerformanceSchema = z.object({\n agentId: z.string(),\n totalVotes: z.number().int().nonnegative(),\n correctVotes: z.number().int().nonnegative(),\n successRate: z.number().min(0).max(1),\n lastUpdated: z.iso.datetime(),\n});\n\n/**\n * Proposal content caching configuration for determinism. (Issue #589)\n */\nexport interface ProposalCacheConfig {\n /** Enable content-based caching for repeated proposals */\n enabled: boolean;\n /** TTL in milliseconds (default: 1 hour) */\n ttlMs: number;\n /** Maximum cached entries (default: 500) */\n maxEntries: number;\n}\n\n/**\n * Incremental quorum configuration (Issue #1408).\n * When enabled, ambiguous votes trigger voter pool expansion.\n */\nexport interface IncrementalQuorumConfig {\n /** Enable incremental quorum expansion. Default: false */\n enabled: boolean;\n /** Maximum expansion rounds (5→7→9). Default: 2 */\n maxExpansionRounds: number;\n /** Voters to add per expansion round. Default: 2 */\n votersPerExpansion: number;\n /** Minimum average confidence to avoid expansion. Default: 0.6 */\n confidenceThreshold: number;\n /** Ambiguity band: if approval rate is within this of threshold, expand. Default: 0.15 */\n ambiguityBand: number;\n}\n\n/**\n * Default incremental quorum configuration.\n */\nexport const DEFAULT_INCREMENTAL_QUORUM_CONFIG: IncrementalQuorumConfig = {\n enabled: false,\n maxExpansionRounds: 2,\n votersPerExpansion: 2,\n confidenceThreshold: 0.6,\n ambiguityBand: 0.15,\n};\n\n/**\n * Callback to request additional voters for incremental quorum.\n * Returns the IDs of newly added voters.\n */\nexport type VoterExpansionCallback = (\n proposalId: ProposalId,\n currentVoterCount: number,\n requestedCount: number\n) => Promise<readonly string[]>;\n\n/**\n * Consensus engine configuration.\n */\nexport interface ConsensusEngineConfig {\n defaultTimeout: number;\n minVotersForQuorum: number;\n maxActiveProposals: number;\n enablePerformanceTracking: boolean;\n /** Maximum number of closed proposals to retain. Oldest are evicted when exceeded. (Issue #549) */\n maxClosedProposals: number;\n /** Content-based proposal caching for determinism (Issue #589) */\n proposalCache?: ProposalCacheConfig;\n /** Incremental quorum configuration (Issue #1408) */\n incrementalQuorum?: IncrementalQuorumConfig;\n}\n\n/**\n * Proposal cache configuration schema. (Issue #589)\n */\nexport const ProposalCacheConfigSchema = z.object({\n enabled: z.boolean().default(false),\n ttlMs: z.number().int().positive().default(3600000), // 1 hour\n maxEntries: z.number().int().positive().default(500),\n});\n\n/**\n * Consensus engine configuration schema.\n */\nexport const ConsensusEngineConfigSchema = z.object({\n defaultTimeout: z.number().int().positive().default(300000), // 5 minutes\n minVotersForQuorum: z.number().int().positive().default(2),\n maxActiveProposals: z.number().int().positive().default(100),\n enablePerformanceTracking: z.boolean().default(true),\n maxClosedProposals: z.number().int().positive().default(1000), // Issue #549\n proposalCache: ProposalCacheConfigSchema.optional(), // Issue #589\n});\n\n/**\n * Default configuration values.\n */\nexport const DEFAULT_CONSENSUS_CONFIG: ConsensusEngineConfig = {\n defaultTimeout: 300000, // 5 minutes\n minVotersForQuorum: 2,\n maxActiveProposals: 100,\n enablePerformanceTracking: true,\n maxClosedProposals: 1000, // Issue #549: Prevent unbounded memory growth\n};\n\n/**\n * The 2/3 supermajority agreement threshold — the governance constant for\n * \"supermajority\" / Byzantine (2-of-3) quorum. SINGLE SOURCE (#3571): every\n * consensus site that needs a supermajority references this instead of a bare\n * `0.67` literal, so the governance threshold cannot silently drift between\n * modules. (Per-algorithm values like 0.5/1.0 are intentionally NOT centralized\n * — 0.5 is semantically overloaded across several algorithms.)\n */\nexport const SUPERMAJORITY_THRESHOLD = 0.67;\n\n/**\n * Voting thresholds for each algorithm.\n */\nexport const VOTING_THRESHOLDS: Record<ConsensusAlgorithm, number> = {\n simple_majority: 0.5,\n supermajority: SUPERMAJORITY_THRESHOLD,\n unanimous: 1.0,\n proof_of_learning: 0.5, // Uses weighted voting\n opinion_wise: 0.5, // Uses correlation-aware Bayesian aggregation (Issue #333)\n higher_order: 0.5, // Alias for opinion_wise (Issue #514)\n};\n\n/**\n * Internal proposal state managed by the engine.\n */\nexport interface ProposalState {\n proposal: Proposal;\n status: ProposalStatus;\n votes: Map<string, Vote>;\n voteWeights: Map<string, number>;\n startedAt: Date;\n timeoutId?: ReturnType<typeof setTimeout>;\n /** Number of incremental quorum expansions applied (Issue #1408). */\n expansionRounds?: number;\n /**\n * True while a quorum expansion is awaiting its callback for this\n * proposal. Concurrent `vote()` calls check this to avoid double-\n * expanding across the `await` gap (Issue #2861). Per-proposal so\n * independent proposals never block each other.\n */\n expansionInFlight?: boolean;\n}\n\n/**\n * Consensus metrics for monitoring.\n */\nexport interface ConsensusMetrics {\n totalProposals: number;\n approvedProposals: number;\n rejectedProposals: number;\n timedOutProposals: number;\n averageDurationMs: number;\n averageVotesPerProposal: number;\n algorithmUsage: Record<ConsensusAlgorithm, number>;\n}\n\n/**\n * Consensus metrics schema.\n */\nexport const ConsensusMetricsSchema = z.object({\n totalProposals: z.number().int().nonnegative(),\n approvedProposals: z.number().int().nonnegative(),\n rejectedProposals: z.number().int().nonnegative(),\n timedOutProposals: z.number().int().nonnegative(),\n averageDurationMs: z.number().nonnegative(),\n averageVotesPerProposal: z.number().nonnegative(),\n algorithmUsage: z.record(ConsensusAlgorithmSchema, z.number().int().nonnegative()),\n});\n"],"mappings":"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","names":["z","READ_ONLY_TOOLS","AsyncLocalStorage","AsyncLocalStorage","err","z"]}
|