mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 16:25:51 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -13,7 +13,9 @@ describe('InProcessTransport', () => {
|
||||
const [client, server] = createLinkedTransportPair()
|
||||
|
||||
let received: JSONRPCMessage | null = null
|
||||
server.onmessage = (msg) => { received = msg }
|
||||
server.onmessage = msg => {
|
||||
received = msg
|
||||
}
|
||||
|
||||
const message: JSONRPCMessage = {
|
||||
jsonrpc: '2.0',
|
||||
@@ -36,7 +38,9 @@ describe('InProcessTransport', () => {
|
||||
const [client, server] = createLinkedTransportPair()
|
||||
|
||||
let received: JSONRPCMessage | null = null
|
||||
client.onmessage = (msg) => { received = msg }
|
||||
client.onmessage = msg => {
|
||||
received = msg
|
||||
}
|
||||
|
||||
await server.send({ jsonrpc: '2.0', result: 42, id: 1 } as any)
|
||||
|
||||
@@ -50,8 +54,12 @@ describe('InProcessTransport', () => {
|
||||
|
||||
let clientClosed = false
|
||||
let serverClosed = false
|
||||
client.onclose = () => { clientClosed = true }
|
||||
server.onclose = () => { serverClosed = true }
|
||||
client.onclose = () => {
|
||||
clientClosed = true
|
||||
}
|
||||
server.onclose = () => {
|
||||
serverClosed = true
|
||||
}
|
||||
|
||||
await client.close()
|
||||
|
||||
@@ -63,7 +71,9 @@ describe('InProcessTransport', () => {
|
||||
const [client] = createLinkedTransportPair()
|
||||
|
||||
let closeCount = 0
|
||||
client.onclose = () => { closeCount++ }
|
||||
client.onclose = () => {
|
||||
closeCount++
|
||||
}
|
||||
|
||||
await client.close()
|
||||
await client.close()
|
||||
@@ -75,6 +85,8 @@ describe('InProcessTransport', () => {
|
||||
const [client] = createLinkedTransportPair()
|
||||
await client.close()
|
||||
|
||||
expect(client.send({ jsonrpc: '2.0', method: 'test' } as any)).rejects.toThrow('Transport is closed')
|
||||
expect(
|
||||
client.send({ jsonrpc: '2.0', method: 'test' } as any),
|
||||
).rejects.toThrow('Transport is closed')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,8 +5,11 @@ describe('memoizeWithLRU', () => {
|
||||
test('caches results', () => {
|
||||
let callCount = 0
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => { callCount++; return x * 2 },
|
||||
(x) => `key-${x}`,
|
||||
(x: number) => {
|
||||
callCount++
|
||||
return x * 2
|
||||
},
|
||||
x => `key-${x}`,
|
||||
10,
|
||||
)
|
||||
|
||||
@@ -19,7 +22,7 @@ describe('memoizeWithLRU', () => {
|
||||
test('evicts least recently used entries', () => {
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => x,
|
||||
(x) => `key-${x}`,
|
||||
x => `key-${x}`,
|
||||
2,
|
||||
)
|
||||
|
||||
@@ -36,7 +39,7 @@ describe('memoizeWithLRU', () => {
|
||||
test('cache.clear removes all entries', () => {
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => x,
|
||||
(x) => `key-${x}`,
|
||||
x => `key-${x}`,
|
||||
10,
|
||||
)
|
||||
|
||||
@@ -51,7 +54,7 @@ describe('memoizeWithLRU', () => {
|
||||
test('cache.delete removes specific entry', () => {
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => x,
|
||||
(x) => `key-${x}`,
|
||||
x => `key-${x}`,
|
||||
10,
|
||||
)
|
||||
|
||||
@@ -65,7 +68,7 @@ describe('memoizeWithLRU', () => {
|
||||
test('cache.get returns value without promoting', () => {
|
||||
const fn = memoizeWithLRU(
|
||||
(x: number) => x * 10,
|
||||
(x) => `key-${x}`,
|
||||
x => `key-${x}`,
|
||||
2,
|
||||
)
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ describe('isTerminalConnectionError', () => {
|
||||
})
|
||||
|
||||
test('detects ETIMEDOUT', () => {
|
||||
expect(isTerminalConnectionError('Connection timed out: ETIMEDOUT')).toBe(true)
|
||||
expect(isTerminalConnectionError('Connection timed out: ETIMEDOUT')).toBe(
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
test('detects EPIPE', () => {
|
||||
@@ -29,16 +31,22 @@ describe('isTerminalConnectionError', () => {
|
||||
})
|
||||
|
||||
test('detects EHOSTUNREACH', () => {
|
||||
expect(isTerminalConnectionError('Host unreachable: EHOSTUNREACH')).toBe(true)
|
||||
expect(isTerminalConnectionError('Host unreachable: EHOSTUNREACH')).toBe(
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
test('detects ECONNREFUSED', () => {
|
||||
expect(isTerminalConnectionError('Connection refused: ECONNREFUSED')).toBe(true)
|
||||
expect(isTerminalConnectionError('Connection refused: ECONNREFUSED')).toBe(
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
test('detects SSE disconnection messages', () => {
|
||||
expect(isTerminalConnectionError('SSE stream disconnected')).toBe(true)
|
||||
expect(isTerminalConnectionError('Failed to reconnect SSE stream')).toBe(true)
|
||||
expect(isTerminalConnectionError('Failed to reconnect SSE stream')).toBe(
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
test('detects terminated', () => {
|
||||
@@ -48,13 +56,17 @@ describe('isTerminalConnectionError', () => {
|
||||
test('rejects non-terminal errors', () => {
|
||||
expect(isTerminalConnectionError('some random error')).toBe(false)
|
||||
expect(isTerminalConnectionError('')).toBe(false)
|
||||
expect(isTerminalConnectionError('timeout waiting for response')).toBe(false)
|
||||
expect(isTerminalConnectionError('timeout waiting for response')).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isMcpSessionExpiredError', () => {
|
||||
test('detects 404 with JSON-RPC session-not-found code', () => {
|
||||
const error = new Error('Not found: {"code":-32001,"message":"Session not found"}')
|
||||
const error = new Error(
|
||||
'Not found: {"code":-32001,"message":"Session not found"}',
|
||||
)
|
||||
Object.assign(error, { code: 404 })
|
||||
expect(isMcpSessionExpiredError(error)).toBe(true)
|
||||
})
|
||||
|
||||
@@ -55,11 +55,20 @@ describe('discoverTools', () => {
|
||||
expect(result).toHaveLength(1)
|
||||
const tool = result[0]
|
||||
expect(tool.name).toBe('mcp__my-server__search')
|
||||
expect(tool.mcpInfo).toEqual({ serverName: 'my-server', toolName: 'search' })
|
||||
expect(tool.mcpInfo).toEqual({
|
||||
serverName: 'my-server',
|
||||
toolName: 'search',
|
||||
})
|
||||
expect(tool.isMcp).toBe(true)
|
||||
expect(tool.isReadOnly({} as any)).toBe(true)
|
||||
expect(tool.userFacingName(undefined)).toBe('Search Items')
|
||||
expect(await tool.description({} as any, { isNonInteractiveSession: false, toolPermissionContext: {}, tools: [] })).toBe('Search for items')
|
||||
expect(
|
||||
await tool.description({} as any, {
|
||||
isNonInteractiveSession: false,
|
||||
toolPermissionContext: {},
|
||||
tools: [],
|
||||
}),
|
||||
).toBe('Search for items')
|
||||
})
|
||||
|
||||
test('respects skipPrefix option', async () => {
|
||||
|
||||
@@ -2,7 +2,11 @@ import { describe, expect, test, mock } from 'bun:test'
|
||||
import { createMcpManager } from '../manager.js'
|
||||
import type { McpManager } from '../manager.js'
|
||||
import type { McpClientDependencies } from '../interfaces.js'
|
||||
import type { ScopedMcpServerConfig, MCPServerConnection, ConnectedMCPServer } from '../types.js'
|
||||
import type {
|
||||
ScopedMcpServerConfig,
|
||||
MCPServerConnection,
|
||||
ConnectedMCPServer,
|
||||
} from '../types.js'
|
||||
import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
||||
|
||||
function createMockDeps(): McpClientDependencies {
|
||||
@@ -36,14 +40,17 @@ describe('createMcpManager', () => {
|
||||
|
||||
test('connect throws if connectFn not set', async () => {
|
||||
const manager = createMcpManager(createMockDeps())
|
||||
await expect(manager.connect('test', { command: 'npx', args: [] }))
|
||||
.rejects.toThrow('connectFn not set')
|
||||
await expect(
|
||||
manager.connect('test', { command: 'npx', args: [] }),
|
||||
).rejects.toThrow('connectFn not set')
|
||||
})
|
||||
|
||||
test('connect calls connectFn and emits connected event', async () => {
|
||||
const manager = createMcpManager(createMockDeps()) as any
|
||||
let connectedEvent: string | null = null
|
||||
manager.on('connected', (name: string) => { connectedEvent = name })
|
||||
manager.on('connected', (name: string) => {
|
||||
connectedEvent = name
|
||||
})
|
||||
|
||||
const mockConnection: ConnectedMCPServer = {
|
||||
type: 'connected',
|
||||
@@ -53,17 +60,26 @@ describe('createMcpManager', () => {
|
||||
onclose: null,
|
||||
} as unknown as Client,
|
||||
capabilities: {},
|
||||
config: { command: 'npx', args: [], scope: 'dynamic' } as ScopedMcpServerConfig,
|
||||
config: {
|
||||
command: 'npx',
|
||||
args: [],
|
||||
scope: 'dynamic',
|
||||
} as ScopedMcpServerConfig,
|
||||
cleanup: mock(() => Promise.resolve()),
|
||||
}
|
||||
|
||||
manager.setConnectFn(async (name: string, config: ScopedMcpServerConfig) => {
|
||||
expect(name).toBe('test-server')
|
||||
expect(config.scope).toBe('dynamic')
|
||||
return mockConnection
|
||||
})
|
||||
manager.setConnectFn(
|
||||
async (name: string, config: ScopedMcpServerConfig) => {
|
||||
expect(name).toBe('test-server')
|
||||
expect(config.scope).toBe('dynamic')
|
||||
return mockConnection
|
||||
},
|
||||
)
|
||||
|
||||
const result = await manager.connect('test-server', { command: 'npx', args: [] })
|
||||
const result = await manager.connect('test-server', {
|
||||
command: 'npx',
|
||||
args: [],
|
||||
})
|
||||
expect(result.type).toBe('connected')
|
||||
expect(connectedEvent as unknown as string).toBe('test-server')
|
||||
})
|
||||
@@ -71,15 +87,23 @@ describe('createMcpManager', () => {
|
||||
test('disconnect calls cleanup and emits disconnected', async () => {
|
||||
const manager = createMcpManager(createMockDeps()) as any
|
||||
let disconnected = false
|
||||
manager.on('disconnected', () => { disconnected = true })
|
||||
manager.on('disconnected', () => {
|
||||
disconnected = true
|
||||
})
|
||||
|
||||
const mockCleanup = mock(() => Promise.resolve())
|
||||
const mockConnection: ConnectedMCPServer = {
|
||||
type: 'connected',
|
||||
name: 'test-server',
|
||||
client: { request: mock(() => Promise.resolve({ tools: [] })) } as unknown as Client,
|
||||
client: {
|
||||
request: mock(() => Promise.resolve({ tools: [] })),
|
||||
} as unknown as Client,
|
||||
capabilities: {},
|
||||
config: { command: 'npx', args: [], scope: 'dynamic' } as ScopedMcpServerConfig,
|
||||
config: {
|
||||
command: 'npx',
|
||||
args: [],
|
||||
scope: 'dynamic',
|
||||
} as ScopedMcpServerConfig,
|
||||
cleanup: mockCleanup,
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ describe('normalizeNameForMCP', () => {
|
||||
|
||||
test('collapses underscores for claude.ai prefix', () => {
|
||||
expect(normalizeNameForMCP('claude.ai Slack')).toBe('claude_ai_Slack')
|
||||
expect(normalizeNameForMCP('claude.ai My Server')).toBe('claude_ai_My_Server')
|
||||
expect(normalizeNameForMCP('claude.ai My Server')).toBe(
|
||||
'claude_ai_My_Server',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -33,7 +35,9 @@ describe('buildMcpToolName', () => {
|
||||
})
|
||||
|
||||
test('normalizes server name with dots', () => {
|
||||
expect(buildMcpToolName('test.server', 'tool')).toBe('mcp__test_server__tool')
|
||||
expect(buildMcpToolName('test.server', 'tool')).toBe(
|
||||
'mcp__test_server__tool',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -68,10 +72,12 @@ describe('getMcpPrefix', () => {
|
||||
|
||||
describe('getToolNameForPermissionCheck', () => {
|
||||
test('uses mcp prefix for MCP tools', () => {
|
||||
expect(getToolNameForPermissionCheck({
|
||||
name: 'query',
|
||||
mcpInfo: { serverName: 'my-server', toolName: 'query' },
|
||||
})).toBe('mcp__my-server__query')
|
||||
expect(
|
||||
getToolNameForPermissionCheck({
|
||||
name: 'query',
|
||||
mcpInfo: { serverName: 'my-server', toolName: 'query' },
|
||||
}),
|
||||
).toBe('mcp__my-server__query')
|
||||
})
|
||||
|
||||
test('uses raw name for non-MCP tools', () => {
|
||||
@@ -82,13 +88,17 @@ describe('getToolNameForPermissionCheck', () => {
|
||||
describe('getMcpDisplayName', () => {
|
||||
test('strips MCP prefix', () => {
|
||||
// getMcpDisplayName normalizes server name before building prefix
|
||||
expect(getMcpDisplayName('mcp__my_server__query', 'my.server')).toBe('query')
|
||||
expect(getMcpDisplayName('mcp__my_server__query', 'my.server')).toBe(
|
||||
'query',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('extractMcpToolDisplayName', () => {
|
||||
test('removes MCP suffix', () => {
|
||||
expect(extractMcpToolDisplayName('github - Add comment (MCP)')).toBe('Add comment')
|
||||
expect(extractMcpToolDisplayName('github - Add comment (MCP)')).toBe(
|
||||
'Add comment',
|
||||
)
|
||||
})
|
||||
|
||||
test('handles no dash', () => {
|
||||
@@ -96,6 +106,8 @@ describe('extractMcpToolDisplayName', () => {
|
||||
})
|
||||
|
||||
test('handles no suffix', () => {
|
||||
expect(extractMcpToolDisplayName('github - Add comment')).toBe('Add comment')
|
||||
expect(extractMcpToolDisplayName('github - Add comment')).toBe(
|
||||
'Add comment',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user