* 完善所有用到的type对象,并添加中文注释

* 补充遗失的type

* 修复claude-for-chrome-mcp中的type和interface类型缺失

* 完善注释
This commit is contained in:
xiaoFjun-eng
2026-05-19 15:04:59 +08:00
committed by GitHub
parent ea399f1862
commit 27b665ac79
14 changed files with 194 additions and 60 deletions

View File

@@ -9,6 +9,7 @@ import { SocketConnectionError } from './mcpSocketClient.js'
import {
localPlatformLabel,
type BridgePermissionRequest,
toLoggerDetail,
type ChromeExtensionInfo,
type ClaudeForChromeContext,
type PermissionMode,
@@ -578,7 +579,7 @@ export class BridgeClient implements SocketClient {
const durationMs = Date.now() - this.connectionStartTime
logger.error(
`[${serverName}] Failed to create WebSocket after ${durationMs}ms:`,
error,
toLoggerDetail(error),
)
trackEvent?.('chrome_bridge_connection_failed', {
duration_ms: durationMs,
@@ -618,7 +619,10 @@ export class BridgeClient implements SocketClient {
)
this.handleMessage(message)
} catch (error) {
logger.error(`[${serverName}] Failed to parse bridge message:`, error)
logger.error(
`[${serverName}] Failed to parse bridge message:`,
toLoggerDetail(error),
)
}
})
@@ -862,7 +866,10 @@ export class BridgeClient implements SocketClient {
const allowed = await pending.onPermissionRequest(request)
this.sendPermissionResponse(requestId, allowed)
} catch (error) {
logger.error(`[${serverName}] Error handling permission request:`, error)
logger.error(
`[${serverName}] Error handling permission request:`,
toLoggerDetail(error),
)
this.sendPermissionResponse(requestId, false)
}
}

View File

@@ -8,8 +8,11 @@ export { localPlatformLabel } from './types.js'
export type {
BridgeConfig,
ChromeExtensionInfo,
ChromeBridgeTrackEventMetadata,
ClaudeForChromeContext,
Logger,
LoggerDetail,
PermissionMode,
SocketClient,
} from './types.js'
export { toLoggerDetail } from './types.js'

View File

@@ -9,6 +9,7 @@ import type {
PermissionMode,
PermissionOverrides,
} from './types.js'
import { toLoggerDetail } from './types.js'
export class SocketConnectionError extends Error {
constructor(message: string) {
@@ -87,7 +88,10 @@ class McpSocketClient {
await this.validateSocketSecurity(socketPath)
} catch (error) {
this.connecting = false
logger.info(`[${serverName}] Security validation failed:`, error)
logger.info(
`[${serverName}] Security validation failed:`,
toLoggerDetail(error),
)
// Don't retry on security failures (wrong perms/owner) - those won't
// self-resolve. Only the error handler retries on transient errors.
return
@@ -145,14 +149,20 @@ class McpSocketClient {
logger.info(`[${serverName}] Received unknown message: ${message}`)
}
} catch (error) {
logger.info(`[${serverName}] Failed to parse message:`, error)
logger.info(
`[${serverName}] Failed to parse message:`,
toLoggerDetail(error),
)
}
}
})
this.socket.on('error', (error: Error & { code?: string }) => {
clearTimeout(connectTimeout)
logger.info(`[${serverName}] Socket error (code: ${error.code}):`, error)
logger.info(
`[${serverName}] Socket error (code: ${error.code}):`,
toLoggerDetail(error),
)
this.connected = false
this.connecting = false

View File

@@ -7,6 +7,7 @@ import type {
PermissionOverrides,
SocketClient,
} from './types.js'
import { toLoggerDetail } from './types.js'
export const handleToolCall = async (
context: ClaudeForChromeContext,
@@ -44,7 +45,10 @@ export const handleToolCall = async (
return handleToolCallDisconnected(context)
} catch (error) {
context.logger.info(`[${context.serverName}] Error calling tool:`, error)
context.logger.info(
`[${context.serverName}] Error calling tool:`,
toLoggerDetail(error),
)
if (error instanceof SocketConnectionError) {
return handleToolCallDisconnected(context)
@@ -165,8 +169,7 @@ async function handleToolCallConnected(
// Fallback for unexpected result format
context.logger.warn(
`[${context.serverName}] Unexpected result format from socket bridge`,
response,
`[${context.serverName}] Unexpected result format from socket bridge: ${JSON.stringify(response)}`,
)
return {

View File

@@ -1,11 +1,84 @@
export interface Logger {
info: (message: string, ...args: unknown[]) => void
error: (message: string, ...args: unknown[]) => void
warn: (message: string, ...args: unknown[]) => void
debug: (message: string, ...args: unknown[]) => void
silly: (message: string, ...args: unknown[]) => void
/**
* Logger 第二参数的可选类型。
* 调用方通过 util.format 追加详情,实践中多为 catch 到的异常对象。
*/
export type LoggerDetail = Error | NodeJS.ErrnoException
/** 将 unknown 收窄为 LoggerDetail供 catch 块传给 logger 使用。 */
export function toLoggerDetail(detail: unknown): LoggerDetail | undefined {
return detail instanceof Error ? detail : undefined
}
/** 宿主注入的日志接口,与 DebugLoggerutil.format对齐。 */
export interface Logger {
info: (message: string, detail?: LoggerDetail) => void // 信息
error: (message: string, detail?: LoggerDetail) => void // 错误
warn: (message: string, detail?: LoggerDetail) => void // 警告
debug: (message: string, detail?: LoggerDetail) => void // 调试
silly: (message: string, detail?: LoggerDetail) => void // 最细粒度调试
}
/**
* Bridge 连接失败时的 error_type 枚举。
* 由 bridgeClient 在 getUserId / getOAuthToken / WebSocket 创建失败时上报。
*/
export type ChromeBridgeConnectionErrorType =
| 'no_user_id' // 无法获取用户 UUID
| 'no_oauth_token' // 无法获取 OAuth token
| 'websocket_error' // WebSocket 创建或运行异常
/** 工具调用相关遥测元数据started / completed / timeout / error。 */
export type ChromeBridgeToolCallMetadata = {
tool_name: string // MCP 工具名
tool_use_id: string // 本次调用的 UUID
duration_ms?: number // 耗时(毫秒)
timeout_ms?: number // 超时阈值(毫秒),仅 timeout 事件
error_message?: string // 错误摘要(截断),仅 error 事件
}
/** Bridge 连接失败遥测元数据。 */
export type ChromeBridgeConnectionFailedMetadata = {
duration_ms: number // 自连接开始到失败的耗时(毫秒)
error_type: ChromeBridgeConnectionErrorType // 失败原因分类
reconnect_attempt: number // 当前重连尝试次数
}
/** Bridge 开始连接遥测元数据。 */
export type ChromeBridgeConnectionStartedMetadata = {
bridge_url: string // 目标 WebSocket URL含用户路径
}
/** Bridge 断开连接遥测元数据。 */
export type ChromeBridgeDisconnectedMetadata = {
close_code: number // WebSocket 关闭码
duration_since_connect_ms: number // 自连接成功到断开的时长(毫秒)
reconnect_attempt: number // 即将进行的重连序号
}
/** Bridge 连接成功遥测元数据。 */
export type ChromeBridgeConnectionSucceededMetadata = {
duration_ms: number // 自开始到连接就绪的耗时(毫秒)
status: 'paired' | 'waiting' // paired=已配对扩展waiting=等待扩展接入
}
/** Bridge 重连次数耗尽遥测元数据。 */
export type ChromeBridgeReconnectExhaustedMetadata = {
total_attempts: number // 累计重连次数上限
}
/**
* trackEvent 回调的 metadata 联合类型。
* 各变体对应 bridgeClient 内 chrome_bridge_* 事件null 表示无附加字段。
*/
export type ChromeBridgeTrackEventMetadata =
| ChromeBridgeToolCallMetadata
| ChromeBridgeConnectionFailedMetadata
| ChromeBridgeConnectionStartedMetadata
| ChromeBridgeDisconnectedMetadata
| ChromeBridgeConnectionSucceededMetadata
| ChromeBridgeReconnectExhaustedMetadata
| null // 无元数据(如 peer_connected / peer_disconnected
export type PermissionMode =
| 'ask'
| 'skip_all_permission_checks'
@@ -48,10 +121,10 @@ export interface ClaudeForChromeContext {
bridgeConfig?: BridgeConfig
/** If set, permission mode is sent to the extension immediately on bridge connection. */
initialPermissionMode?: PermissionMode
/** Optional callback to track telemetry events for bridge connections */
trackEvent?: <K extends string>(
eventName: K,
metadata: Record<string, unknown> | null,
/** Bridge 遥测回调eventName 为 chrome_bridge_* 事件名 */
trackEvent?: (
eventName: string, // 事件名
metadata: ChromeBridgeTrackEventMetadata, // 事件元数据
) => void
/** Called when user pairs with an extension via the browser pairing flow. */
onExtensionPaired?: (deviceId: string, name: string) => void

View File

@@ -20,7 +20,7 @@
*/
import type { ScreenshotResult } from './executor.js'
import type { Logger } from './types.js'
import { type Logger, toLoggerDetail } from './types.js'
/** Injected by the host. See `ComputerUseHostAdapter.cropRawPatch`. */
export type CropRawPatchFn = (
@@ -165,7 +165,10 @@ export async function validateClickTarget(
} catch (err) {
// Skip validation on technical errors, execute action anyway.
// Battle-tested: validation failure must never block the click.
logger.debug('[pixelCompare] validation error, skipping', err)
logger.debug(
'[pixelCompare] validation error, skipping',
toLoggerDetail(err),
)
return { valid: true, skipped: true }
}
}

View File

@@ -91,6 +91,7 @@ import type {
ResolvedAppRequest,
TeachStepRequest,
} from './types.js'
import { toLoggerDetail } from './types.js'
/**
* Finder is never hidden by the hide loop (hiding Finder kills the Desktop),
@@ -4446,7 +4447,10 @@ export async function handleToolCall(
// For ungated tools, the executor may have been mid-call; that's fine —
// the result is still a tool error, never an implicit success.
const msg = err instanceof Error ? err.message : String(err)
logger.error(`[${serverName}] tool=${name} threw: ${msg}`, err)
logger.error(
`[${serverName}] tool=${name} threw: ${msg}`,
toLoggerDetail(err),
)
return errorResult(`Tool "${name}" failed: ${msg}`, 'executor_threw')
}
}

View File

@@ -8,13 +8,24 @@ import type {
* cross-respawn `scaleCoord` survival. */
export type ScreenshotDims = Omit<ScreenshotResult, 'base64'>
/** Shape mirrors claude-for-chrome-mcp/src/types.ts:1-7 */
/**
* Logger 第二参数的可选类型(与 claude-for-chrome-mcp 对齐)。
* 实践中多为 catch 到的 Error。
*/
export type LoggerDetail = Error | NodeJS.ErrnoException
/** 将 unknown 收窄为 LoggerDetail供 catch 块传给 logger 使用。 */
export function toLoggerDetail(detail: unknown): LoggerDetail | undefined {
return detail instanceof Error ? detail : undefined
}
/** 宿主注入的日志接口(与 claude-for-chrome-mcp/src/types.ts 对齐)。 */
export interface Logger {
info: (message: string, ...args: unknown[]) => void
error: (message: string, ...args: unknown[]) => void
warn: (message: string, ...args: unknown[]) => void
debug: (message: string, ...args: unknown[]) => void
silly: (message: string, ...args: unknown[]) => void
info: (message: string, detail?: LoggerDetail) => void // 信息
error: (message: string, detail?: LoggerDetail) => void // 错误
warn: (message: string, detail?: LoggerDetail) => void // 警告
debug: (message: string, detail?: LoggerDetail) => void // 调试
silly: (message: string, detail?: LoggerDetail) => void // 最细粒度调试
}
/**

View File

@@ -1,3 +1,4 @@
import type { EventHandlerProps } from './events/event-handlers.js'
import type { FocusManager } from './focus.js'
import { createLayoutNode } from './layout/engine.js'
import type { LayoutNode } from './layout/node.js'
@@ -45,10 +46,9 @@ export type DOMElement = {
dirty: boolean
// Set by the reconciler's hideInstance/unhideInstance; survives style updates.
isHidden?: boolean
// Event handlers set by the reconciler for the capture/bubble dispatcher.
// Stored separately from attributes so handler identity changes don't
// mark dirty and defeat the blit optimization.
_eventHandlers?: Record<string, unknown>
// 协调器写入的事件处理器(捕获/冒泡分发用)。
// attributes 分离,避免 handler 引用变化触发 dirty 破坏 blit 优化。
_eventHandlers?: Partial<EventHandlerProps> // 见 event-handlers.ts EventHandlerProps
// Scroll state for overflow: 'scroll' boxes. scrollTop is the number of
// rows the content is scrolled down by. scrollHeight/scrollViewportHeight

View File

@@ -101,7 +101,10 @@ export class TerminalEvent extends Event {
_prepareForTarget(_target: EventTarget): void {}
}
import type { EventHandlerProps } from './event-handlers.js'
/** 终端事件系统的目标节点DOM 树节点或根节点)。 */
export type EventTarget = {
parentNode: EventTarget | undefined
_eventHandlers?: Record<string, unknown>
parentNode: EventTarget | undefined // 父节点,根节点为 undefined
_eventHandlers?: Partial<EventHandlerProps> // 事件处理器,与 dom.ts DOMElement 同构
}

View File

@@ -20,7 +20,10 @@ import {
type TextNode,
} from './dom.js'
import { Dispatcher } from './events/dispatcher.js'
import { EVENT_HANDLER_PROPS } from './events/event-handlers.js'
import {
EVENT_HANDLER_PROPS,
type EventHandlerProps,
} from './events/event-handlers.js'
import { getFocusManager, getRootNode } from './focus.js'
import { LayoutDisplay } from './layout/node.js'
import applyStyles, { type Styles, type TextStyles } from './styles.js'
@@ -111,7 +114,11 @@ type HostContext = {
isInsideText: boolean
}
function setEventHandler(node: DOMElement, key: string, value: unknown): void {
function setEventHandler<K extends keyof EventHandlerProps>(
node: DOMElement,
key: K,
value: EventHandlerProps[K],
): void {
if (!node._eventHandlers) {
node._eventHandlers = {}
}
@@ -135,7 +142,11 @@ function applyProp(node: DOMElement, key: string, value: unknown): void {
}
if (EVENT_HANDLER_PROPS.has(key)) {
setEventHandler(node, key, value)
setEventHandler(
node,
key as keyof EventHandlerProps,
value as EventHandlerProps[keyof EventHandlerProps],
)
return
}
@@ -441,7 +452,11 @@ const reconciler = createReconciler<
}
if (EVENT_HANDLER_PROPS.has(key)) {
setEventHandler(node, key, value)
setEventHandler(
node,
key as keyof EventHandlerProps,
value as EventHandlerProps[keyof EventHandlerProps],
)
continue
}

View File

@@ -1897,12 +1897,12 @@ export function getAccountInformation() {
accountInfo.apiKeySource = apiKeySource
}
// We don't know the organization if we're relying on an external API key or auth token
// 如果我们依赖外部 API 密钥或认证令牌,则不知道组织
if (
authTokenSource === 'claude.ai' ||
apiKeySource === '/login managed key'
) {
// Get organization name from OAuth account info
// 从 OAuth 账户信息获取组织名称
const orgName = getOauthAccountInfo()?.organizationName
if (orgName) {
accountInfo.organization = orgName

View File

@@ -2,6 +2,7 @@ import {
type ClaudeForChromeContext,
createClaudeForChromeMcpServer,
type Logger,
type LoggerDetail,
type PermissionMode,
} from '@ant/claude-for-chrome-mcp'
import { initializeAnalyticsSink } from '../../services/analytics/sink.js'
@@ -276,19 +277,19 @@ export async function runClaudeInChromeMcpServer(): Promise<void> {
}
class DebugLogger implements Logger {
silly(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'debug' })
silly(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'debug' })
}
debug(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'debug' })
debug(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'debug' })
}
info(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'info' })
info(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'info' })
}
warn(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'warn' })
warn(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'warn' })
}
error(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'error' })
error(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'error' })
}
}

View File

@@ -1,6 +1,7 @@
import type {
ComputerUseHostAdapter,
Logger,
LoggerDetail,
} from '@ant/computer-use-mcp/types'
import { format } from 'util'
import { logForDebugging } from '../debug.js'
@@ -10,20 +11,20 @@ import { getChicagoEnabled, getChicagoSubGates } from './gates.js'
import { requireComputerUseSwift } from './swiftLoader.js'
class DebugLogger implements Logger {
silly(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'debug' })
silly(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'debug' })
}
debug(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'debug' })
debug(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'debug' })
}
info(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'info' })
info(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'info' })
}
warn(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'warn' })
warn(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'warn' })
}
error(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'error' })
error(message: string, detail?: LoggerDetail): void {
logForDebugging(format(message, detail ?? ''), { level: 'error' })
}
}