chore: initialize qiming workspace repository
This commit is contained in:
557
qimingclaw/crates/agent-electron-client/src/preload/index.ts
Normal file
557
qimingclaw/crates/agent-electron-client/src/preload/index.ts
Normal file
@@ -0,0 +1,557 @@
|
||||
import { contextBridge, ipcRenderer } from "electron";
|
||||
import type { SandboxPolicy } from "@shared/types/sandbox";
|
||||
|
||||
// Expose protected methods to the renderer process
|
||||
contextBridge.exposeInMainWorld("electronAPI", {
|
||||
// Process info (available in preload but not in renderer)
|
||||
versions: {
|
||||
node: process.versions.node,
|
||||
electron: process.versions.electron,
|
||||
chrome: process.versions.chrome,
|
||||
},
|
||||
|
||||
// Settings
|
||||
settings: {
|
||||
get: (key: string) => ipcRenderer.invoke("settings:get", key),
|
||||
set: (key: string, value: unknown) =>
|
||||
ipcRenderer.invoke("settings:set", key, value),
|
||||
},
|
||||
|
||||
// Window controls
|
||||
window: {
|
||||
minimize: () => ipcRenderer.invoke("window:minimize"),
|
||||
maximize: () => ipcRenderer.invoke("window:maximize"),
|
||||
close: () => ipcRenderer.invoke("window:close"),
|
||||
},
|
||||
|
||||
// MCP Proxy management (qiming-mcp-stdio-proxy 聚合代理)
|
||||
mcp: {
|
||||
start: () => ipcRenderer.invoke("mcp:start"),
|
||||
stop: () => ipcRenderer.invoke("mcp:stop"),
|
||||
restart: () => ipcRenderer.invoke("mcp:restart"),
|
||||
status: () => ipcRenderer.invoke("mcp:status"),
|
||||
getConfig: () => ipcRenderer.invoke("mcp:getConfig"),
|
||||
setConfig: (config: {
|
||||
mcpServers: Record<
|
||||
string,
|
||||
{ command: string; args: string[]; env?: Record<string, string> }
|
||||
>;
|
||||
}) => ipcRenderer.invoke("mcp:setConfig", config),
|
||||
discoverTools: (serverId: string) =>
|
||||
ipcRenderer.invoke("mcp:discoverTools", serverId),
|
||||
exportConfig: () => ipcRenderer.invoke("mcp:exportConfig"),
|
||||
getPort: () => Promise.resolve(0),
|
||||
setPort: (_port: number) => Promise.resolve({ success: true }),
|
||||
},
|
||||
|
||||
// Lanproxy management (via IPC to main process)
|
||||
lanproxy: {
|
||||
start: (config: {
|
||||
serverIp: string;
|
||||
serverPort: number;
|
||||
clientKey: string;
|
||||
ssl?: boolean;
|
||||
}) => ipcRenderer.invoke("lanproxy:start", config),
|
||||
stop: () => ipcRenderer.invoke("lanproxy:stop"),
|
||||
status: () => ipcRenderer.invoke("lanproxy:status"),
|
||||
isAvailable: () =>
|
||||
ipcRenderer.invoke("lanproxy:isAvailable") as Promise<{
|
||||
available: boolean;
|
||||
}>,
|
||||
},
|
||||
|
||||
// Agent Runner management (via IPC to main process)
|
||||
agentRunner: {
|
||||
start: (config: {
|
||||
binPath: string;
|
||||
backendPort: number;
|
||||
proxyPort: number;
|
||||
apiKey: string;
|
||||
apiBaseUrl: string;
|
||||
defaultModel: string;
|
||||
}) => ipcRenderer.invoke("agentRunner:start", config),
|
||||
stop: () => ipcRenderer.invoke("agentRunner:stop"),
|
||||
status: () => ipcRenderer.invoke("agentRunner:status"),
|
||||
},
|
||||
|
||||
// Sandbox policy and diagnostics
|
||||
sandbox: {
|
||||
status: () => ipcRenderer.invoke("sandbox:status"),
|
||||
getPolicy: () => ipcRenderer.invoke("sandbox:policy:get"),
|
||||
setPolicy: (patch: Partial<SandboxPolicy>) =>
|
||||
ipcRenderer.invoke("sandbox:policy:set", patch),
|
||||
capabilities: () => ipcRenderer.invoke("sandbox:capabilities"),
|
||||
setup: () => ipcRenderer.invoke("sandbox:setup"),
|
||||
},
|
||||
|
||||
// Agent - unified ACP service (claude-code/qimingcode)
|
||||
agent: {
|
||||
// Unified Agent ACP
|
||||
init: (config: any) => ipcRenderer.invoke("agent:init", config),
|
||||
destroy: () => ipcRenderer.invoke("agent:destroy"),
|
||||
getEngineType: () => ipcRenderer.invoke("agent:getEngineType"),
|
||||
isReady: () => ipcRenderer.invoke("agent:isReady"),
|
||||
serviceStatus: () => ipcRenderer.invoke("agent:serviceStatus"),
|
||||
|
||||
// Session management (ACP)
|
||||
listSessions: () => ipcRenderer.invoke("agent:listSessions"),
|
||||
createSession: (opts?: { parentID?: string; title?: string }) =>
|
||||
ipcRenderer.invoke("agent:createSession", opts),
|
||||
getSession: (id: string) => ipcRenderer.invoke("agent:getSession", id),
|
||||
deleteSession: (id: string) =>
|
||||
ipcRenderer.invoke("agent:deleteSession", id),
|
||||
updateSession: (id: string, title?: string) =>
|
||||
ipcRenderer.invoke("agent:updateSession", id, title),
|
||||
getSessionStatus: () => ipcRenderer.invoke("agent:getSessionStatus"),
|
||||
forkSession: (id: string, messageId?: string) =>
|
||||
ipcRenderer.invoke("agent:forkSession", id, messageId),
|
||||
|
||||
// Messages
|
||||
getMessages: (sessionId: string, limit?: number) =>
|
||||
ipcRenderer.invoke("agent:getMessages", sessionId, limit),
|
||||
getMessage: (sessionId: string, messageId: string) =>
|
||||
ipcRenderer.invoke("agent:getMessage", sessionId, messageId),
|
||||
|
||||
// Prompt / Command / Shell
|
||||
prompt: (sessionId: string, parts: any[], opts?: any) =>
|
||||
ipcRenderer.invoke("agent:prompt", sessionId, parts, opts),
|
||||
promptAsync: (sessionId: string, parts: any[], opts?: any) =>
|
||||
ipcRenderer.invoke("agent:promptAsync", sessionId, parts, opts),
|
||||
command: (sessionId: string, cmd: string, args?: string, opts?: any) =>
|
||||
ipcRenderer.invoke("agent:command", sessionId, cmd, args, opts),
|
||||
shell: (sessionId: string, cmd: string, agent?: string, model?: any) =>
|
||||
ipcRenderer.invoke("agent:shell", sessionId, cmd, agent, model),
|
||||
|
||||
// Abort
|
||||
abort: (sessionId: string) => ipcRenderer.invoke("agent:abort", sessionId),
|
||||
|
||||
// Permission
|
||||
respondPermission: (
|
||||
sessionId: string,
|
||||
permissionId: string,
|
||||
response: "once" | "always" | "reject",
|
||||
) =>
|
||||
ipcRenderer.invoke(
|
||||
"agent:respondPermission",
|
||||
sessionId,
|
||||
permissionId,
|
||||
response,
|
||||
),
|
||||
|
||||
// Session operations
|
||||
getSessionDiff: (sessionId: string, messageId?: string) =>
|
||||
ipcRenderer.invoke("agent:getSessionDiff", sessionId, messageId),
|
||||
revert: (sessionId: string, messageId: string, partId?: string) =>
|
||||
ipcRenderer.invoke("agent:revert", sessionId, messageId, partId),
|
||||
unrevert: (sessionId: string) =>
|
||||
ipcRenderer.invoke("agent:unrevert", sessionId),
|
||||
shareSession: (sessionId: string) =>
|
||||
ipcRenderer.invoke("agent:shareSession", sessionId),
|
||||
|
||||
// Tools
|
||||
listTools: (provider?: string, model?: string) =>
|
||||
ipcRenderer.invoke("agent:listTools", provider, model),
|
||||
|
||||
// Providers
|
||||
listProviders: () => ipcRenderer.invoke("agent:listProviders"),
|
||||
|
||||
// Config
|
||||
getConfig: () => ipcRenderer.invoke("agent:getConfig"),
|
||||
|
||||
// File operations
|
||||
findText: (pattern: string) =>
|
||||
ipcRenderer.invoke("agent:findText", pattern),
|
||||
findFiles: (query: string, dirs?: boolean) =>
|
||||
ipcRenderer.invoke("agent:findFiles", query, dirs),
|
||||
listFiles: (dirPath: string) =>
|
||||
ipcRenderer.invoke("agent:listFiles", dirPath),
|
||||
readFile: (filePath: string) =>
|
||||
ipcRenderer.invoke("agent:readFile", filePath),
|
||||
|
||||
// MCP via ACP
|
||||
mcpStatus: () => ipcRenderer.invoke("agent:mcpStatus"),
|
||||
|
||||
// Agents & Commands
|
||||
listAgents: () => ipcRenderer.invoke("agent:listAgents"),
|
||||
listCommands: () => ipcRenderer.invoke("agent:listCommands"),
|
||||
|
||||
// Claude Code specific
|
||||
claudePrompt: (message: string) =>
|
||||
ipcRenderer.invoke("agent:claudePrompt", message),
|
||||
|
||||
// Sessions tab (detailed view)
|
||||
listSessionsDetailed: () =>
|
||||
ipcRenderer.invoke("agent:listSessionsDetailed"),
|
||||
stopSession: (sessionId: string) =>
|
||||
ipcRenderer.invoke("agent:stopSession", sessionId),
|
||||
|
||||
// SSE Event listening
|
||||
onEvent: (
|
||||
callback: (event: any, data: { type: string; data: any }) => void,
|
||||
) => {
|
||||
ipcRenderer.on("agent:event", callback);
|
||||
},
|
||||
offEvent: (
|
||||
callback: (event: any, data: { type: string; data: any }) => void,
|
||||
) => {
|
||||
ipcRenderer.removeListener("agent:event", callback);
|
||||
},
|
||||
},
|
||||
|
||||
// File Server management
|
||||
fileServer: {
|
||||
start: (port?: number) => ipcRenderer.invoke("fileServer:start", port),
|
||||
stop: () => ipcRenderer.invoke("fileServer:stop"),
|
||||
status: () => ipcRenderer.invoke("fileServer:status"),
|
||||
},
|
||||
|
||||
// Computer Server lifecycle (Agent HTTP 接口服务)
|
||||
computerServer: {
|
||||
start: (port?: number) => ipcRenderer.invoke("computerServer:start", port),
|
||||
stop: () => ipcRenderer.invoke("computerServer:stop"),
|
||||
status: () => ipcRenderer.invoke("computerServer:status"),
|
||||
},
|
||||
|
||||
// GUI Agent Server lifecycle (桌面自动化视觉操作服务)
|
||||
guiServer: {
|
||||
start: () => ipcRenderer.invoke("guiServer:start"),
|
||||
stop: () => ipcRenderer.invoke("guiServer:stop"),
|
||||
status: () => ipcRenderer.invoke("guiServer:status"),
|
||||
isEnabled: () => ipcRenderer.invoke("guiServer:isEnabled"),
|
||||
setEnabled: (enabled: boolean) =>
|
||||
ipcRenderer.invoke("guiServer:setEnabled", enabled),
|
||||
},
|
||||
|
||||
// Admin Server lifecycle (管理接口服务)
|
||||
adminServer: {
|
||||
start: (port?: number) => ipcRenderer.invoke("adminServer:start", port),
|
||||
stop: () => ipcRenderer.invoke("adminServer:stop"),
|
||||
status: () => ipcRenderer.invoke("adminServer:status"),
|
||||
},
|
||||
|
||||
// Computer API (对齐 rcoder /computer/* API)
|
||||
computer: {
|
||||
chat: (request: any) => ipcRenderer.invoke("computer:chat", request),
|
||||
agentStatus: (request: any) =>
|
||||
ipcRenderer.invoke("computer:agentStatus", request),
|
||||
agentStop: (request: any) =>
|
||||
ipcRenderer.invoke("computer:agentStop", request),
|
||||
cancelSession: (request: any) =>
|
||||
ipcRenderer.invoke("computer:cancelSession", request),
|
||||
health: () => ipcRenderer.invoke("computer:health"),
|
||||
onProgress: (callback: any) => {
|
||||
ipcRenderer.on("computer:progress", callback);
|
||||
},
|
||||
offProgress: (callback: any) => {
|
||||
ipcRenderer.removeListener("computer:progress", callback);
|
||||
},
|
||||
},
|
||||
|
||||
// Services (对齐 Tauri services_restart_all)
|
||||
services: {
|
||||
restartAll: () => ipcRenderer.invoke("services:restartAll"),
|
||||
stopAll: () => ipcRenderer.invoke("services:stopAll"),
|
||||
},
|
||||
|
||||
// Tray status sync
|
||||
tray: {
|
||||
updateStatus: (status: "running" | "stopped" | "error" | "starting") =>
|
||||
ipcRenderer.invoke("tray:updateStatus", status),
|
||||
updateServicesStatus: (running: boolean) =>
|
||||
ipcRenderer.invoke("tray:updateServicesStatus", running),
|
||||
},
|
||||
|
||||
// Dependency management
|
||||
dependencies: {
|
||||
checkAll: (options?: { checkLatest?: boolean }) =>
|
||||
ipcRenderer.invoke("dependencies:checkAll", options),
|
||||
checkNode: () => ipcRenderer.invoke("dependencies:checkNode"),
|
||||
checkUv: () => ipcRenderer.invoke("dependencies:checkUv"),
|
||||
checkMcpProxyBundled: () =>
|
||||
ipcRenderer.invoke("dependencies:checkMcpProxyBundled"),
|
||||
checkQimingCodeBundled: () =>
|
||||
ipcRenderer.invoke("dependencies:checkQimingCodeBundled"),
|
||||
checkClaudeCodeAcpBundled: () =>
|
||||
ipcRenderer.invoke("dependencies:checkClaudeCodeAcpBundled"),
|
||||
checkQimingFileServerBundled: () =>
|
||||
ipcRenderer.invoke("dependencies:checkQimingFileServerBundled"),
|
||||
detectPackage: (packageName: string, binName?: string) =>
|
||||
ipcRenderer.invoke("dependencies:detectPackage", packageName, binName),
|
||||
installPackage: (
|
||||
packageName: string,
|
||||
options?: { registry?: string; version?: string },
|
||||
) =>
|
||||
ipcRenderer.invoke("dependencies:installPackage", packageName, options),
|
||||
installMissing: () => ipcRenderer.invoke("dependencies:installMissing"),
|
||||
getAppDataDir: () => ipcRenderer.invoke("dependencies:getAppDataDir"),
|
||||
getRequiredList: () => ipcRenderer.invoke("dependencies:getRequiredList"),
|
||||
},
|
||||
|
||||
// Engine Manager (claude-code / qimingcode)
|
||||
engine: {
|
||||
checkLocal: (engine: string) =>
|
||||
ipcRenderer.invoke("engine:checkLocal", engine),
|
||||
checkGlobal: (engine: string) =>
|
||||
ipcRenderer.invoke("engine:checkGlobal", engine),
|
||||
getVersion: (engine: string) =>
|
||||
ipcRenderer.invoke("engine:getVersion", engine),
|
||||
findBinary: (engine: string) =>
|
||||
ipcRenderer.invoke("engine:findBinary", engine),
|
||||
install: (engine: string, options?: { registry?: string }) =>
|
||||
ipcRenderer.invoke("engine:install", engine, options),
|
||||
start: (config: {
|
||||
engine: string;
|
||||
apiKey?: string;
|
||||
baseUrl?: string;
|
||||
model?: string;
|
||||
workspaceDir?: string;
|
||||
}) => ipcRenderer.invoke("engine:start", config),
|
||||
stop: (engineId: string) => ipcRenderer.invoke("engine:stop", engineId),
|
||||
status: (engineId?: string) =>
|
||||
ipcRenderer.invoke("engine:status", engineId),
|
||||
send: (engineId: string, message: string) =>
|
||||
ipcRenderer.invoke("engine:send", engineId, message),
|
||||
stopAll: () => ipcRenderer.invoke("engine:stopAll"),
|
||||
},
|
||||
|
||||
// Shell utilities
|
||||
shell: {
|
||||
openExternal: (url: string) =>
|
||||
ipcRenderer.invoke("shell:openExternal", url),
|
||||
// 打开本地目录/文件到系统文件管理器,供设置页“打开工作空间目录”等功能复用。
|
||||
openPath: (targetPath: string) =>
|
||||
ipcRenderer.invoke("shell:openPath", targetPath),
|
||||
},
|
||||
|
||||
// Session / Cookie management (for embedded webview)
|
||||
session: {
|
||||
setCookie: (params: {
|
||||
url: string;
|
||||
name: string;
|
||||
value: string;
|
||||
domain?: string;
|
||||
httpOnly?: boolean;
|
||||
secure?: boolean;
|
||||
}) => ipcRenderer.invoke("session:setCookie", params),
|
||||
getCookie: (params: { url: string; name: string }) =>
|
||||
ipcRenderer.invoke("session:getCookie", params),
|
||||
removeCookie: (params: { url: string; name: string }) =>
|
||||
ipcRenderer.invoke("session:removeCookie", params),
|
||||
flushStore: () => ipcRenderer.invoke("session:flushStore"),
|
||||
},
|
||||
|
||||
// WebView Window - 独立窗口打开会话浏览器
|
||||
webview: {
|
||||
openWindow: (params: { url: string; title?: string }) =>
|
||||
ipcRenderer.invoke("webview:openWindow", params) as Promise<{
|
||||
success: boolean;
|
||||
reused?: boolean;
|
||||
error?: string;
|
||||
}>,
|
||||
closeWindow: () =>
|
||||
ipcRenderer.invoke("webview:closeWindow") as Promise<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}>,
|
||||
isWindowOpen: () =>
|
||||
ipcRenderer.invoke("webview:isWindowOpen") as Promise<boolean>,
|
||||
},
|
||||
|
||||
// Mirror / Registry
|
||||
mirror: {
|
||||
get: () => ipcRenderer.invoke("mirror:get"),
|
||||
set: (config: { npmRegistry?: string; uvIndexUrl?: string }) =>
|
||||
ipcRenderer.invoke("mirror:set", config),
|
||||
},
|
||||
|
||||
// i18n - 语言同步
|
||||
i18n: {
|
||||
getLang: () => ipcRenderer.invoke("i18n:getLang"),
|
||||
setLang: (lang: string) => {
|
||||
console.debug(`[preload] i18n.setLang("${lang}")`);
|
||||
return ipcRenderer.invoke("i18n:setLang", lang);
|
||||
},
|
||||
},
|
||||
|
||||
// Dialog utilities
|
||||
dialog: {
|
||||
openDirectory: (title?: string) =>
|
||||
ipcRenderer.invoke("dialog:openDirectory", title),
|
||||
},
|
||||
|
||||
// Autolaunch
|
||||
autolaunch: {
|
||||
get: () => ipcRenderer.invoke("autolaunch:get"),
|
||||
set: (enabled: boolean) => ipcRenderer.invoke("autolaunch:set", enabled),
|
||||
},
|
||||
|
||||
// Long-term Memory
|
||||
memory: {
|
||||
// Lifecycle
|
||||
init: (workspaceDir: string, config?: any) =>
|
||||
ipcRenderer.invoke("memory:init", workspaceDir, config),
|
||||
destroy: () => ipcRenderer.invoke("memory:destroy"),
|
||||
status: () => ipcRenderer.invoke("memory:status"),
|
||||
ensureReady: () =>
|
||||
ipcRenderer.invoke("memory:ensureReady") as Promise<{
|
||||
ready: boolean;
|
||||
synced: boolean;
|
||||
}>,
|
||||
|
||||
// Configuration
|
||||
getConfig: () => ipcRenderer.invoke("memory:getConfig"),
|
||||
updateConfig: (config: any) =>
|
||||
ipcRenderer.invoke("memory:updateConfig", config),
|
||||
|
||||
// Extraction
|
||||
extract: (
|
||||
sessionId: string,
|
||||
messageId: string,
|
||||
messages: any[],
|
||||
modelConfig: any,
|
||||
) =>
|
||||
ipcRenderer.invoke(
|
||||
"memory:extract",
|
||||
sessionId,
|
||||
messageId,
|
||||
messages,
|
||||
modelConfig,
|
||||
),
|
||||
append: (content: string, title?: string) =>
|
||||
ipcRenderer.invoke("memory:append", content, title),
|
||||
handleMessage: (
|
||||
message: { role: "user" | "assistant"; content: string },
|
||||
sessionId: string,
|
||||
modelConfig: any,
|
||||
) =>
|
||||
ipcRenderer.invoke(
|
||||
"memory:handleMessage",
|
||||
message,
|
||||
sessionId,
|
||||
modelConfig,
|
||||
) as Promise<{ success: boolean; error?: string }>,
|
||||
onSessionEnd: (sessionId: string, modelConfig: any) =>
|
||||
ipcRenderer.invoke(
|
||||
"memory:onSessionEnd",
|
||||
sessionId,
|
||||
modelConfig,
|
||||
) as Promise<{ success: boolean; taskId?: string; error?: string }>,
|
||||
getExtractionProgress: (sessionId: string) =>
|
||||
ipcRenderer.invoke("memory:getExtractionProgress", sessionId) as Promise<{
|
||||
success: boolean;
|
||||
progress?: any[];
|
||||
error?: string;
|
||||
}>,
|
||||
|
||||
// Retrieval
|
||||
search: (query: string, options?: any) =>
|
||||
ipcRenderer.invoke("memory:search", query, options),
|
||||
getContext: (query: string, options?: any) =>
|
||||
ipcRenderer.invoke("memory:getContext", query, options),
|
||||
|
||||
// File operations
|
||||
sync: () => ipcRenderer.invoke("memory:sync"),
|
||||
rebuildIndex: () => ipcRenderer.invoke("memory:rebuildIndex"),
|
||||
getFiles: () => ipcRenderer.invoke("memory:getFiles"),
|
||||
|
||||
// Management
|
||||
add: (entry: any) => ipcRenderer.invoke("memory:add", entry),
|
||||
update: (id: string, updates: any) =>
|
||||
ipcRenderer.invoke("memory:update", id, updates),
|
||||
delete: (id: string) => ipcRenderer.invoke("memory:delete", id),
|
||||
list: (options?: any) => ipcRenderer.invoke("memory:list", options),
|
||||
|
||||
// Scheduled tasks
|
||||
runConsolidation: (modelConfig?: {
|
||||
provider: string;
|
||||
model: string;
|
||||
apiKey: string;
|
||||
baseUrl?: string;
|
||||
}) => ipcRenderer.invoke("memory:runConsolidation", modelConfig),
|
||||
runCleanup: () => ipcRenderer.invoke("memory:runCleanup"),
|
||||
|
||||
// Vector
|
||||
checkVectorSupport: () => ipcRenderer.invoke("memory:checkVectorSupport"),
|
||||
setEmbeddingConfig: (config: any) =>
|
||||
ipcRenderer.invoke("memory:setEmbeddingConfig", config),
|
||||
|
||||
// Queue status
|
||||
getQueueStatus: () => ipcRenderer.invoke("memory:getQueueStatus"),
|
||||
getSchedulerStatus: () => ipcRenderer.invoke("memory:getSchedulerStatus"),
|
||||
},
|
||||
|
||||
// Log
|
||||
log: {
|
||||
getDir: () => ipcRenderer.invoke("log:getDir"),
|
||||
openDir: () => ipcRenderer.invoke("log:openDir"),
|
||||
list: (count?: number, offset?: number) =>
|
||||
ipcRenderer.invoke("log:list", count, offset),
|
||||
write: (
|
||||
level: "info" | "warn" | "error",
|
||||
message: string,
|
||||
...args: unknown[]
|
||||
) => ipcRenderer.invoke("log:write", level, message, ...args),
|
||||
},
|
||||
|
||||
// App
|
||||
app: {
|
||||
checkUpdate: () => ipcRenderer.invoke("app:checkUpdate"),
|
||||
getVersion: () => ipcRenderer.invoke("app:getVersion"),
|
||||
downloadUpdate: () => ipcRenderer.invoke("app:downloadUpdate"),
|
||||
installUpdate: () => ipcRenderer.invoke("app:installUpdate"),
|
||||
getUpdateState: () => ipcRenderer.invoke("app:getUpdateState"),
|
||||
openReleasesPage: () => ipcRenderer.invoke("app:openReleasesPage"),
|
||||
getUpdateDebugInfo: () => ipcRenderer.invoke("app:getUpdateDebugInfo"),
|
||||
getDeviceId: () => ipcRenderer.invoke("app:getDeviceId"),
|
||||
},
|
||||
|
||||
// Permissions (macOS)
|
||||
permissions: {
|
||||
check: () => ipcRenderer.invoke("permissions:check"),
|
||||
openSettings: (permissionKey: string) =>
|
||||
ipcRenderer.invoke("permissions:openSettings", permissionKey),
|
||||
},
|
||||
|
||||
// Quick Init — 读取快捷初始化配置
|
||||
quickInit: {
|
||||
getConfig: () => ipcRenderer.invoke("quickInit:getConfig"),
|
||||
},
|
||||
|
||||
// Event listeners
|
||||
// 保存 callback → wrapper 映射,使 off() 能正确移除 on() 注册的 listener
|
||||
on: (channel: string, callback: (...args: unknown[]) => void) => {
|
||||
const validChannels = [
|
||||
"menu:new-session",
|
||||
"menu:settings",
|
||||
"menu:mcp-settings",
|
||||
"menu:dependencies",
|
||||
"cowork:message",
|
||||
"cowork:permission",
|
||||
"agent:event",
|
||||
"computer:progress",
|
||||
"update:status",
|
||||
"deps:syncCompleted",
|
||||
"autolaunch:changed",
|
||||
"memory:sync",
|
||||
"memory:consolidation",
|
||||
"memory:cleanup",
|
||||
"admin:servicesRestarting",
|
||||
"admin:servicesRestarted",
|
||||
];
|
||||
if (validChannels.includes(channel)) {
|
||||
const wrapper = (_: unknown, ...args: unknown[]) => callback(...args);
|
||||
(callback as any).__ipcWrapper = wrapper;
|
||||
ipcRenderer.on(channel, wrapper as any);
|
||||
}
|
||||
},
|
||||
|
||||
off: (channel: string, callback: (...args: unknown[]) => void) => {
|
||||
const wrapper = (callback as any).__ipcWrapper || callback;
|
||||
ipcRenderer.removeListener(channel, wrapper);
|
||||
},
|
||||
|
||||
// PERF 专用日志(fire-and-forget,写入主进程 perf.YYYY-MM-DD.log)
|
||||
perf: {
|
||||
log: (msg: string) => ipcRenderer.send("perf:log", msg),
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user