Skip to main content
Glama
ClaudeCodeAdapter.test.ts6.67 kB
/** * Tests for ClaudeCodeAdapter */ import { describe, test, expect, beforeEach } from 'vitest'; import { ClaudeCodeAdapter } from '../../src/adapters/ClaudeCodeAdapter'; describe('ClaudeCodeAdapter', () => { let adapter: ClaudeCodeAdapter; beforeEach(() => { adapter = new ClaudeCodeAdapter(); }); describe('parseInput', () => { test('parses Claude Code stdin format with all fields', () => { const input = JSON.stringify({ tool_name: 'Read', tool_input: { file_path: '/test/file.ts', limit: 100 }, cwd: '/workspace', session_id: 'session-123', hook_event_name: 'PreToolUse', tool_use_id: 'tool-use-123', transcript_path: '/path/to/transcript.txt', permission_mode: 'ask', llm_tool: 'claude-code', }); const context = adapter.parseInput(input); expect(context.tool_name).toBe('Read'); expect(context.tool_input).toEqual({ file_path: '/test/file.ts', limit: 100 }); expect(context.cwd).toBe('/workspace'); expect(context.session_id).toBe('session-123'); expect(context.llm_tool).toBe('claude-code'); expect(context.hook_event_name).toBe('PreToolUse'); }); test.each([ ['Write', { file_path: '/test/file.ts', content: 'test' }], ['Edit', { file_path: '/test/file.ts', old_string: 'old', new_string: 'new' }], ['Read', { file_path: '/test/file.ts' }], ])('parses %s tool correctly', (toolName, toolInput) => { const input = JSON.stringify({ tool_name: toolName, tool_input: toolInput, cwd: '/workspace', session_id: 'session-test', hook_event_name: 'PreToolUse', tool_use_id: 'tool-use-test', transcript_path: '/path/to/transcript.txt', permission_mode: 'ask', }); const context = adapter.parseInput(input); expect(context.tool_name).toBe(toolName); expect(context.tool_input).toEqual(toolInput); }); test('parses non-file tools correctly', () => { const input = JSON.stringify({ tool_name: 'Bash', tool_input: { command: 'ls -la' }, cwd: '/workspace', session_id: 'session-999', hook_event_name: 'PreToolUse', tool_use_id: 'tool-use-999', transcript_path: '/path/to/transcript.txt', permission_mode: 'ask', }); const context = adapter.parseInput(input); expect(context.tool_name).toBe('Bash'); expect(context.tool_input).toEqual({ command: 'ls -la' }); }); test('handles missing optional llm_tool field', () => { const input = JSON.stringify({ tool_name: 'Read', tool_input: { file_path: '/test/file.ts' }, cwd: '/workspace', session_id: 'session-111', hook_event_name: 'PreToolUse', tool_use_id: 'tool-use-111', transcript_path: '/path/to/transcript.txt', permission_mode: 'ask', }); const context = adapter.parseInput(input); expect(context.llm_tool).toBeUndefined(); }); test('throws error on invalid JSON', () => { expect(() => adapter.parseInput('invalid json')).toThrow(); }); }); describe('formatOutput', () => { test.each([ ['allow', 'Operation allowed'], ['deny', 'Operation denied'], ['ask', 'User confirmation needed'], ])('formats %s decision', (decision, message) => { // Parse input first to set PreToolUse mode const input = JSON.stringify({ tool_name: 'Read', tool_input: { file_path: '/test/file.ts' }, cwd: '/workspace', session_id: 'session-123', hook_event_name: 'PreToolUse', tool_use_id: 'tool-use-123', transcript_path: '/path/to/transcript.txt', permission_mode: 'ask', }); adapter.parseInput(input); const response = { decision: decision as 'allow' | 'deny' | 'ask', message, }; const output = adapter.formatOutput(response); const parsed = JSON.parse(output); expect(parsed.hookSpecificOutput.permissionDecision).toBe(decision); expect(parsed.hookSpecificOutput.permissionDecisionReason).toBe(message); expect(parsed.hookSpecificOutput.hookEventName).toBe('PreToolUse'); }); test('formats skip decision as empty object', () => { // Parse input first const input = JSON.stringify({ tool_name: 'Read', tool_input: { file_path: '/test/file.ts' }, cwd: '/workspace', session_id: 'session-123', hook_event_name: 'PreToolUse', tool_use_id: 'tool-use-123', transcript_path: '/path/to/transcript.txt', permission_mode: 'ask', }); adapter.parseInput(input); const response = { decision: 'skip' as const, message: '', }; const output = adapter.formatOutput(response); const parsed = JSON.parse(output); expect(parsed).toEqual({}); }); test('includes updatedInput when provided', () => { // Parse input first const input = JSON.stringify({ tool_name: 'Write', tool_input: { file_path: '/test/file.ts', content: 'old content' }, cwd: '/workspace', session_id: 'session-123', hook_event_name: 'PreToolUse', tool_use_id: 'tool-use-123', transcript_path: '/path/to/transcript.txt', permission_mode: 'ask', }); adapter.parseInput(input); const response = { decision: 'allow' as const, message: 'Updated parameters', updatedInput: { file_path: '/updated/file.ts', content: 'new content' }, }; const output = adapter.formatOutput(response); const parsed = JSON.parse(output); expect(parsed.hookSpecificOutput.updatedInput).toEqual({ file_path: '/updated/file.ts', content: 'new content', }); }); test('excludes updatedInput when not provided', () => { // Parse input first const input = JSON.stringify({ tool_name: 'Read', tool_input: { file_path: '/test/file.ts' }, cwd: '/workspace', session_id: 'session-123', hook_event_name: 'PreToolUse', tool_use_id: 'tool-use-123', transcript_path: '/path/to/transcript.txt', permission_mode: 'ask', }); adapter.parseInput(input); const response = { decision: 'allow' as const, message: 'No updates', }; const output = adapter.formatOutput(response); const parsed = JSON.parse(output); expect(parsed.hookSpecificOutput.updatedInput).toBeUndefined(); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AgiFlow/aicode-toolkit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server