cc-haha/src/utils/computerUse/hostAdapter.ts
程序员阿江(Relakkes) e8f42840a2 feat: enable Computer Use with Python bridge replacing private native modules
Bypass all three gating layers (compile-time feature flag, subscription
check, GrowthBook remote config) and replace Anthropic's private native
modules (@ant/computer-use-swift, @ant/computer-use-input) with a Python
bridge using pyautogui + mss + pyobjc. Works on any macOS with any
Anthropic-protocol compatible model.
2026-04-03 18:33:31 +08:00

54 lines
2.0 KiB
TypeScript

import type {
ComputerUseHostAdapter,
Logger,
} from '../../vendor/computer-use-mcp/types.js'
import { format } from 'util'
import { logForDebugging } from '../debug.js'
import { COMPUTER_USE_MCP_SERVER_NAME } from './common.js'
import { createCliExecutor } from './executor.js'
import { getChicagoEnabled, getChicagoSubGates } from './gates.js'
import { callPythonHelper } from './pythonBridge.js'
class DebugLogger implements Logger {
silly(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'debug' })
}
debug(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'debug' })
}
info(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'info' })
}
warn(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'warn' })
}
error(message: string, ...args: unknown[]): void {
logForDebugging(format(message, ...args), { level: 'error' })
}
}
let cached: ComputerUseHostAdapter | undefined
export function getComputerUseHostAdapter(): ComputerUseHostAdapter {
if (cached) return cached
cached = {
serverName: COMPUTER_USE_MCP_SERVER_NAME,
logger: new DebugLogger(),
executor: createCliExecutor({
getMouseAnimationEnabled: () => getChicagoSubGates().mouseAnimation,
getHideBeforeActionEnabled: () => getChicagoSubGates().hideBeforeAction,
}),
ensureOsPermissions: async () => {
const perms = await callPythonHelper<{ accessibility: boolean; screenRecording: boolean }>('check_permissions', {})
return perms.accessibility && perms.screenRecording
? { granted: true as const }
: { granted: false as const, accessibility: perms.accessibility, screenRecording: perms.screenRecording }
},
isDisabled: () => !getChicagoEnabled(),
getSubGates: getChicagoSubGates,
getAutoUnhideEnabled: () => true,
cropRawPatch: () => null,
}
return cached
}