source dump of claude code
at main 79 lines 3.1 kB view raw
1import { feature } from 'bun:bundle' 2import partition from 'lodash-es/partition.js' 3import uniqBy from 'lodash-es/uniqBy.js' 4import { COORDINATOR_MODE_ALLOWED_TOOLS } from '../constants/tools.js' 5import { isMcpTool } from '../services/mcp/utils.js' 6import type { Tool, ToolPermissionContext, Tools } from '../Tool.js' 7 8// MCP tool name suffixes for PR activity subscription. These are lightweight 9// orchestration actions the coordinator calls directly rather than delegating 10// to workers. Matched by suffix since the MCP server name prefix may vary. 11const PR_ACTIVITY_TOOL_SUFFIXES = [ 12 'subscribe_pr_activity', 13 'unsubscribe_pr_activity', 14] 15 16export function isPrActivitySubscriptionTool(name: string): boolean { 17 return PR_ACTIVITY_TOOL_SUFFIXES.some(suffix => name.endsWith(suffix)) 18} 19 20// Dead code elimination: conditional imports for feature-gated modules 21/* eslint-disable @typescript-eslint/no-require-imports */ 22const coordinatorModeModule = feature('COORDINATOR_MODE') 23 ? (require('../coordinator/coordinatorMode.js') as typeof import('../coordinator/coordinatorMode.js')) 24 : null 25/* eslint-enable @typescript-eslint/no-require-imports */ 26 27/** 28 * Filters a tool array to the set allowed in coordinator mode. 29 * Shared between the REPL path (mergeAndFilterTools) and the headless 30 * path (main.tsx) so both stay in sync. 31 * 32 * PR activity subscription tools are always allowed since subscription 33 * management is orchestration. 34 */ 35export function applyCoordinatorToolFilter(tools: Tools): Tools { 36 return tools.filter( 37 t => 38 COORDINATOR_MODE_ALLOWED_TOOLS.has(t.name) || 39 isPrActivitySubscriptionTool(t.name), 40 ) 41} 42 43/** 44 * Pure function that merges tool pools and applies coordinator mode filtering. 45 * 46 * Lives in a React-free file so print.ts can import it without pulling 47 * react/ink into the SDK module graph. The useMergedTools hook delegates 48 * to this function inside useMemo. 49 * 50 * @param initialTools - Extra tools to include (built-in + startup MCP from props). 51 * @param assembled - Tools from assembleToolPool (built-in + MCP, deduped). 52 * @param mode - The permission context mode. 53 * @returns Merged, deduplicated, and coordinator-filtered tool array. 54 */ 55export function mergeAndFilterTools( 56 initialTools: Tools, 57 assembled: Tools, 58 mode: ToolPermissionContext['mode'], 59): Tools { 60 // Merge initialTools on top - they take precedence in deduplication. 61 // initialTools may include built-in tools (from getTools() in REPL.tsx) which 62 // overlap with assembled tools. uniqBy handles this deduplication. 63 // Partition-sort for prompt-cache stability (same as assembleToolPool): 64 // built-ins must stay a contiguous prefix for the server's cache policy. 65 const [mcp, builtIn] = partition( 66 uniqBy([...initialTools, ...assembled], 'name'), 67 isMcpTool, 68 ) 69 const byName = (a: Tool, b: Tool) => a.name.localeCompare(b.name) 70 const tools = [...builtIn.sort(byName), ...mcp.sort(byName)] 71 72 if (feature('COORDINATOR_MODE') && coordinatorModeModule) { 73 if (coordinatorModeModule.isCoordinatorMode()) { 74 return applyCoordinatorToolFilter(tools) 75 } 76 } 77 78 return tools 79}