multica/apps/desktop/electron/electron-env.d.ts
Naiyuan Qing 607adeb667 feat(desktop): implement local chat with direct IPC and mode switching
Add LocalChat component using useLocalChat hook that communicates with
the Hub via IPC (no Gateway required). Fix streamId extraction to use
event.message.id matching Hub behavior. Fix history to return raw
AgentMessageItem[] instead of flattened strings. Add exec approval
forwarding over IPC. Use conditional rendering for LocalChat to prevent
event leaking from remote sessions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:50:55 +08:00

210 lines
6 KiB
TypeScript

/// <reference types="vite-plugin-electron/electron-env" />
declare namespace NodeJS {
interface ProcessEnv {
/**
* The built directory structure
*
* ```tree
* ├─┬─┬ dist
* │ │ └── index.html
* │ │
* │ ├─┬ dist-electron
* │ │ ├── main.js
* │ │ └── preload.js
* │
* ```
*/
APP_ROOT: string
/** /dist/ or /public/ */
VITE_PUBLIC: string
}
}
// ============================================================================
// ElectronAPI type definitions
// ============================================================================
interface HubStatus {
hubId: string
status: string
agentCount: number
gatewayConnected: boolean
gatewayUrl?: string
defaultAgent?: {
agentId: string
status: string
} | null
}
interface AgentInfo {
agentId: string
status: string
}
interface ToolInfo {
name: string
group: string
enabled: boolean
}
interface SkillInfo {
id: string
name: string
description: string
version: string
enabled: boolean
source: 'bundled' | 'global' | 'profile'
triggers: string[]
}
interface DeviceMeta {
userAgent?: string
platform?: string
language?: string
}
interface DeviceEntryInfo {
deviceId: string
agentId: string
addedAt: number
meta?: DeviceMeta
}
interface SkillAddResult {
ok: boolean
message: string
path?: string
skills?: string[]
}
interface ProfileData {
profileId: string | undefined
name: string | undefined
style: string | undefined
userContent: string | undefined
}
interface LocalChatEvent {
agentId: string
streamId?: string
type?: 'error'
content?: string
event?: {
type: 'message_start' | 'message_update' | 'message_end' | 'tool_execution_start' | 'tool_execution_end'
id?: string
message?: {
role: string
content?: Array<{ type: string; text?: string }>
}
[key: string]: unknown
}
}
interface LocalChatApproval {
approvalId: string
agentId: string
command: string
cwd?: string
riskLevel: 'safe' | 'needs-review' | 'dangerous'
riskReasons: string[]
expiresAtMs: number
}
interface ProviderStatus {
id: string
name: string
authMethod: 'api-key' | 'oauth'
available: boolean
configured: boolean
current: boolean
defaultModel: string
models: string[]
loginUrl?: string
loginCommand?: string
loginInstructions?: string
}
interface CurrentProviderInfo {
provider: string
model: string | undefined
providerName: string | undefined
available: boolean
}
interface ElectronAPI {
hub: {
init: () => Promise<unknown>
getStatus: () => Promise<HubStatus>
getAgentInfo: () => Promise<AgentInfo | null>
info: () => Promise<unknown>
reconnect: (url: string) => Promise<unknown>
listAgents: () => Promise<unknown>
createAgent: (id?: string) => Promise<unknown>
getAgent: (id: string) => Promise<unknown>
closeAgent: (id: string) => Promise<unknown>
sendMessage: (agentId: string, content: string) => Promise<unknown>
registerToken: (token: string, agentId: string, expiresAt: number) => Promise<unknown>
onDeviceConfirmRequest: (callback: (deviceId: string, meta?: DeviceMeta) => void) => void
offDeviceConfirmRequest: () => void
deviceConfirmResponse: (deviceId: string, allowed: boolean) => void
listDevices: () => Promise<DeviceEntryInfo[]>
revokeDevice: (deviceId: string) => Promise<{ ok: boolean }>
onConnectionStateChanged: (callback: (state: string) => void) => void
offConnectionStateChanged: () => void
onDevicesChanged: (callback: () => void) => void
offDevicesChanged: () => void
}
tools: {
list: () => Promise<ToolInfo[]>
toggle: (name: string) => Promise<unknown>
setStatus: (name: string, enabled: boolean) => Promise<unknown>
active: () => Promise<unknown>
reload: () => Promise<unknown>
}
skills: {
list: () => Promise<SkillInfo[]>
get: (id: string) => Promise<unknown>
toggle: (id: string) => Promise<unknown>
setStatus: (id: string, enabled: boolean) => Promise<unknown>
reload: () => Promise<unknown>
add: (source: string, options?: { name?: string; force?: boolean }) => Promise<SkillAddResult>
remove: (name: string) => Promise<SkillAddResult>
}
agent: {
status: () => Promise<unknown>
}
profile: {
get: () => Promise<ProfileData>
updateName: (name: string) => Promise<unknown>
updateStyle: (style: string) => Promise<unknown>
updateUser: (content: string) => Promise<unknown>
}
provider: {
list: () => Promise<ProviderStatus[]>
listAvailable: () => Promise<ProviderStatus[]>
current: () => Promise<CurrentProviderInfo>
set: (providerId: string, modelId?: string) => Promise<{ ok: boolean; provider?: string; model?: string; error?: string }>
getMeta: (providerId: string) => Promise<unknown>
isAvailable: (providerId: string) => Promise<boolean>
saveApiKey: (providerId: string, apiKey: string) => Promise<{ ok: boolean; error?: string }>
importOAuth: (providerId: string) => Promise<{ ok: boolean; expiresAt?: number; error?: string }>
}
localChat: {
subscribe: (agentId: string) => Promise<{ ok?: boolean; error?: string; alreadySubscribed?: boolean }>
unsubscribe: (agentId: string) => Promise<{ ok: boolean }>
getHistory: (agentId: string) => Promise<{ messages: unknown[] }>
send: (agentId: string, content: string) => Promise<{ ok?: boolean; error?: string }>
resolveExecApproval: (approvalId: string, decision: string) => Promise<{ ok: boolean }>
onEvent: (callback: (event: LocalChatEvent) => void) => void
offEvent: () => void
onApproval: (callback: (approval: LocalChatApproval) => void) => void
offApproval: () => void
}
}
// Used in Renderer process, expose in `preload.ts`
interface Window {
ipcRenderer: import('electron').IpcRenderer
electronAPI: ElectronAPI
}