All files / src/components/tools classifyTool.ts

94.44% Statements 17/18
87.5% Branches 7/8
100% Functions 2/2
94.44% Lines 17/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136                                                  65x                         277x       277x 150x 150x 150x 150x 150x         127x 127x 6x 6x 6x     121x     65x                                                                                                                                           147x 147x    
/**
 * Classifies a tool name into a rendering category.
 *
 * Maps tool names from all supported runtimes (Claude Code, Copilot, Codex)
 * to a UI category that determines which card component renders the event.
 */
 
/** Tool rendering categories corresponding to specialized card components. */
export type ToolCategory =
  | "file-read"
  | "file-edit"
  | "file-write"
  | "shell"
  | "search"
  | "todo"
  | "metadata"
  | "task"
  | "workpad"
  | "knowledge"
  | "ipc"
  | "tool-search"
  | "agent"
  | "generic";
 
/** Known MCP server names for bare-name extraction from Copilot dash format. */
const KNOWN_MCP_SERVERS: Set<string> = new Set(["grackle"]);
 
/**
 * Extracts the bare tool name from runtime-specific naming conventions.
 *
 * - Claude Code / Codex: `mcp__grackle__task_create` -> `task_create`
 * - Copilot: `grackle-task_create` -> `task_create`
 * - Built-in: `Read` -> `read` (unchanged, lowered later)
 */
export function extractBareName(toolName: string): string {
  // Defensive: callers may pass undefined for legacy events that never carried
  // a tool name (e.g. stub fixtures, runtimes that emit tool_use with only
  // tool_name / display_name in `content`). Treat as empty string.
  Iif (!toolName) {
    return "";
  }
  // MCP double-underscore format: mcp__<server>__<tool> (only for known servers)
  if (toolName.startsWith("mcp__")) {
    const serverSep = toolName.indexOf("__", 5);
    if (serverSep > 5) {
      const server = toolName.slice(5, serverSep);
      if (KNOWN_MCP_SERVERS.has(server)) {
        return toolName.slice(serverSep + 2);
      }
    }
  }
  // Copilot dash format: <server>-<tool> (only for known servers)
  const dashIndex = toolName.indexOf("-");
  if (dashIndex > 0) {
    const server = toolName.slice(0, dashIndex);
    if (KNOWN_MCP_SERVERS.has(server)) {
      return toolName.slice(dashIndex + 1);
    }
  }
  return toolName;
}
 
const TOOL_MAP: Record<string, ToolCategory> = {
  // File read — Claude Code: Read, Copilot: view
  read: "file-read",
  view: "file-read",
 
  // File edit — Claude Code: Edit, Copilot: edit, Codex: file_change
  edit: "file-edit",
  file_change: "file-edit",
 
  // File write — Claude Code: Write
  write: "file-write",
 
  // Shell — Claude Code: Bash, Copilot: powershell, Codex: command_execution
  bash: "shell",
  powershell: "shell",
  command_execution: "shell",
 
  // Search — Claude Code: Grep, Glob
  grep: "search",
  glob: "search",
 
  // Todo — Claude Code: TodoWrite, Codex: update_plan, Goose: todo_write
  todowrite: "todo",
  update_plan: "todo",
  todo_write: "todo",
 
  // Metadata — Copilot: report_intent
  report_intent: "metadata",
 
  // Task — Grackle MCP
  task_list: "task",
  task_create: "task",
  task_show: "task",
  task_update: "task",
  task_start: "task",
  task_complete: "task",
  task_resume: "task",
  task_delete: "task",
 
  // Workpad — Grackle MCP
  workpad_write: "workpad",
  workpad_read: "workpad",
 
  // Knowledge — Grackle MCP
  knowledge_search: "knowledge",
  knowledge_get_node: "knowledge",
  knowledge_create_node: "knowledge",
 
  // IPC — Grackle MCP
  ipc_spawn: "ipc",
  ipc_write: "ipc",
  ipc_close: "ipc",
  ipc_list_fds: "ipc",
  ipc_terminate: "ipc",
  ipc_create_stream: "ipc",
  ipc_attach: "ipc",
  ipc_share_stream: "ipc",
  ipc_list_streams: "ipc",
 
  // ToolSearch — Claude Code built-in
  toolsearch: "tool-search",
 
  // Agent — Claude Code: Agent (formerly Task), Copilot: task, read_agent
  agent: "agent",
  task: "agent",
  read_agent: "agent",
};
 
/** Classifies a tool name to determine which card component should render it. */
export function classifyTool(toolName: string): ToolCategory {
  const bare = extractBareName(toolName);
  return TOOL_MAP[bare.toLowerCase()] ?? "generic";
}