cc-haha/desktop/src/api/computerUse.ts
程序员阿江(Relakkes) b31be5161c feat: support custom Computer Use Python interpreters
Computer Use setup could fail on machines where PATH discovery misses a valid Python installation, especially Windows or conda-style environments. Store an optional interpreter path, prefer it during environment checks and venv creation, and expose a desktop settings control for selecting or clearing it.

Constraint: Python discovery is environment-specific and cannot always be inferred from PATH.
Rejected: Continue falling back to PATH after an invalid custom path | hides a user-selected broken interpreter and makes diagnosis ambiguous.
Confidence: high
Scope-risk: moderate
Directive: Preserve unknown Computer Use config fields and keep blank interpreter paths normalized to automatic detection.
Tested: bun test src/utils/computerUse/preauthorizedConfig.test.ts src/server/__tests__/computer-use-python.test.ts src/server/__tests__/computer-use-api.test.ts
Tested: cd desktop && bun run test src/pages/ComputerUseSettings.test.tsx
Tested: cd desktop && bun run lint
Tested: cd desktop && bun run build
Tested: Computer Use browser smoke saved /opt/homebrew/bin/python3 and backend persisted then reset pythonPath to null
Not-tested: Full bun run check:server; existing cron-scheduler-launcher test expects CLAUDE_CODE_ENTRYPOINT=sdk-cli but received undefined.
Related: https://github.com/NanmiCoder/cc-haha/issues/331
2026-05-09 21:46:11 +08:00

81 lines
1.7 KiB
TypeScript

import { api } from './client'
export type ComputerUseStatus = {
platform: string
supported: boolean
python: {
installed: boolean
version: string | null
path: string | null
source: 'custom' | 'system' | 'venv' | null
error: string | null
}
venv: {
created: boolean
path: string
}
dependencies: {
installed: boolean
requirementsFound: boolean
}
permissions: {
accessibility: boolean | null
screenRecording: boolean | null
}
}
export type SetupStep = {
name: string
ok: boolean
message: string
}
export type SetupResult = {
success: boolean
steps: SetupStep[]
}
export type InstalledApp = {
bundleId: string
displayName: string
path: string
}
export type AuthorizedApp = {
bundleId: string
displayName: string
authorizedAt: string
}
export type ComputerUseConfig = {
enabled: boolean
authorizedApps: AuthorizedApp[]
grantFlags: {
clipboardRead: boolean
clipboardWrite: boolean
systemKeyCombos: boolean
}
pythonPath: string | null
}
export const computerUseApi = {
getStatus() {
return api.get<ComputerUseStatus>('/api/computer-use/status')
},
runSetup() {
return api.post<SetupResult>('/api/computer-use/setup', undefined, { timeout: 300_000 })
},
getInstalledApps() {
return api.get<{ apps: InstalledApp[] }>('/api/computer-use/apps')
},
getAuthorizedApps() {
return api.get<ComputerUseConfig>('/api/computer-use/authorized-apps')
},
setAuthorizedApps(config: Partial<ComputerUseConfig>) {
return api.put<{ ok: true }>('/api/computer-use/authorized-apps', config)
},
openSettings(pane: 'Privacy_ScreenCapture' | 'Privacy_Accessibility') {
return api.post<{ ok: true }>('/api/computer-use/open-settings', { pane })
},
}