initial commit
This commit is contained in:
94
src/main/index.ts
Normal file
94
src/main/index.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { app, BrowserWindow, ipcMain } from 'electron'
|
||||
import path from 'path'
|
||||
import Store from 'electron-store'
|
||||
import { Provider, AppConfig } from '../shared/types'
|
||||
import { checkProviderStatus, switchProvider, getClaudeCodeConfig } from './services'
|
||||
|
||||
const store = new Store<AppConfig>()
|
||||
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
|
||||
function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false
|
||||
},
|
||||
titleBarStyle: 'hiddenInset',
|
||||
autoHideMenuBar: true
|
||||
})
|
||||
|
||||
if (app.isPackaged) {
|
||||
mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'))
|
||||
} else {
|
||||
mainWindow.loadURL('http://localhost:3000')
|
||||
mainWindow.webContents.openDevTools()
|
||||
}
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
// IPC handlers
|
||||
ipcMain.handle('getProviders', () => {
|
||||
return store.get('providers', {})
|
||||
})
|
||||
|
||||
ipcMain.handle('getCurrentProvider', () => {
|
||||
return store.get('current', '')
|
||||
})
|
||||
|
||||
ipcMain.handle('addProvider', (_, provider: Provider) => {
|
||||
const providers = store.get('providers', {})
|
||||
providers[provider.id] = provider
|
||||
store.set('providers', providers)
|
||||
return true
|
||||
})
|
||||
|
||||
ipcMain.handle('deleteProvider', (_, id: string) => {
|
||||
const providers = store.get('providers', {})
|
||||
delete providers[id]
|
||||
store.set('providers', providers)
|
||||
return true
|
||||
})
|
||||
|
||||
ipcMain.handle('checkStatus', async (_, provider: Provider) => {
|
||||
return await checkProviderStatus(provider)
|
||||
})
|
||||
|
||||
ipcMain.handle('switchProvider', async (_, providerId: string) => {
|
||||
const providers = store.get('providers', {})
|
||||
const provider = providers[providerId]
|
||||
if (provider) {
|
||||
const success = await switchProvider(provider)
|
||||
if (success) {
|
||||
store.set('current', providerId)
|
||||
}
|
||||
return success
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
ipcMain.handle('getClaudeCodeConfigPath', () => {
|
||||
return getClaudeCodeConfig().path
|
||||
})
|
||||
12
src/main/preload.ts
Normal file
12
src/main/preload.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { contextBridge, ipcRenderer } from 'electron'
|
||||
import { Provider } from '../shared/types'
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
getProviders: () => ipcRenderer.invoke('getProviders'),
|
||||
getCurrentProvider: () => ipcRenderer.invoke('getCurrentProvider'),
|
||||
addProvider: (provider: Provider) => ipcRenderer.invoke('addProvider', provider),
|
||||
deleteProvider: (id: string) => ipcRenderer.invoke('deleteProvider', id),
|
||||
checkStatus: (provider: Provider) => ipcRenderer.invoke('checkStatus', provider),
|
||||
switchProvider: (providerId: string) => ipcRenderer.invoke('switchProvider', providerId),
|
||||
getClaudeCodeConfigPath: () => ipcRenderer.invoke('getClaudeCodeConfigPath')
|
||||
})
|
||||
86
src/main/services.ts
Normal file
86
src/main/services.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import axios from 'axios'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
import { Provider, ProviderStatus } from '../shared/types'
|
||||
|
||||
export async function checkProviderStatus(provider: Provider): Promise<ProviderStatus> {
|
||||
const startTime = Date.now()
|
||||
|
||||
try {
|
||||
// 简单的健康检查请求
|
||||
const response = await axios.post(
|
||||
`${provider.apiUrl}/v1/messages`,
|
||||
{
|
||||
model: provider.model || 'claude-3-opus-20240229',
|
||||
messages: [{ role: 'user', content: 'Hi' }],
|
||||
max_tokens: 1
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'x-api-key': provider.apiKey,
|
||||
'anthropic-version': '2023-06-01',
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
timeout: 5000
|
||||
}
|
||||
)
|
||||
|
||||
const responseTime = Date.now() - startTime
|
||||
|
||||
return {
|
||||
isOnline: true,
|
||||
responseTime,
|
||||
lastChecked: new Date()
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
isOnline: false,
|
||||
responseTime: -1,
|
||||
lastChecked: new Date(),
|
||||
error: error instanceof Error ? error.message : '未知错误'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getClaudeCodeConfig() {
|
||||
// Claude Code 配置文件路径
|
||||
const configDir = path.join(os.homedir(), '.claude')
|
||||
const configPath = path.join(configDir, 'settings.json')
|
||||
|
||||
return { path: configPath, dir: configDir }
|
||||
}
|
||||
|
||||
export async function switchProvider(provider: Provider): Promise<boolean> {
|
||||
try {
|
||||
const { path: configPath, dir: configDir } = getClaudeCodeConfig()
|
||||
|
||||
// 确保目录存在
|
||||
await fs.mkdir(configDir, { recursive: true })
|
||||
|
||||
// 读取现有配置
|
||||
let config: any = {}
|
||||
try {
|
||||
const content = await fs.readFile(configPath, 'utf-8')
|
||||
config = JSON.parse(content)
|
||||
} catch {
|
||||
// 文件不存在或解析失败,使用空配置
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
config.api = {
|
||||
...config.api,
|
||||
baseURL: provider.apiUrl,
|
||||
apiKey: provider.apiKey,
|
||||
model: provider.model
|
||||
}
|
||||
|
||||
// 写回配置文件
|
||||
await fs.writeFile(configPath, JSON.stringify(config, null, 2))
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('切换供应商失败:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user