// 契约边界(已冻结):把主进程能力安全暴露给前端 window.api const { contextBridge, ipcRenderer } = require("electron"); contextBridge.exposeInMainWorld("api", { scanLocal: () => ipcRenderer.invoke("scan-local"), pickDir: () => ipcRenderer.invoke("pick-dir"), packLocal: (rels, destDir) => ipcRenderer.invoke("pack-local", { rels, destDir }), upload: (rels, repo, token, isPrivate) => ipcRenderer.invoke("upload", { rels, repo, token, isPrivate }), marketList: () => ipcRenderer.invoke("market-list"), marketInstall: (entry) => ipcRenderer.invoke("market-install", { entry }), // —— 技能商店(cocoloop 镜像)—— skillCatalog: () => ipcRenderer.invoke("skill-catalog"), skillInstall: (skill) => ipcRenderer.invoke("skill-install", { skill }), skillInstalled: (opts) => ipcRenderer.invoke("skill-installed", opts || {}), skillUninstall: (dir) => ipcRenderer.invoke("skill-uninstall", { dir }), skillMigrate: () => ipcRenderer.invoke("skill-migrate"), // —— 插件市场(tokendun 官方插件,自建 gitea)—— pluginCatalog: () => ipcRenderer.invoke("plugin-catalog"), pluginInstall: (plugin) => ipcRenderer.invoke("plugin-install", { plugin }), pluginInstalled: (opts) => ipcRenderer.invoke("plugin-installed", opts || {}), pluginUninstall: (rel) => ipcRenderer.invoke("plugin-uninstall", { rel }), pluginMigrate: () => ipcRenderer.invoke("plugin-migrate"), // —— Codex 安装器 —— codexInstallerInfo: () => ipcRenderer.invoke("codex-installer-info"), codexDownloadInstaller: (platform) => ipcRenderer.invoke("codex-download-installer", { platform }), codexCancelInstallerDownload: (platform) => ipcRenderer.invoke("codex-cancel-installer-download", { platform }), codexInstallWindows: () => ipcRenderer.invoke("codex-install-windows"), codexInstallMac: () => ipcRenderer.invoke("codex-install-mac"), onCodexInstallerProgress: (cb) => { const handler = (_e, p) => cb(p); ipcRenderer.on("codex-installer-progress", handler); return () => ipcRenderer.removeListener("codex-installer-progress", handler); }, // —— 热更新 —— hotCheck: () => ipcRenderer.invoke("hot-check"), hotApply: () => ipcRenderer.invoke("hot-apply"), hotConfirm: () => ipcRenderer.invoke("hot-confirm"), hotRestart: () => ipcRenderer.invoke("hot-restart"), onHotProgress: (cb) => { const handler = (_e, p) => cb(p); ipcRenderer.on("hot-progress", handler); return () => ipcRenderer.removeListener("hot-progress", handler); }, ghPull: (repoInput, token) => ipcRenderer.invoke("gh-pull", { repoInput, token }), ghRestore: (rels, enable) => ipcRenderer.invoke("gh-restore", { rels, enable }), getSecret: (name) => ipcRenderer.invoke("get-secret", { name }), setSecret: (name, value) => ipcRenderer.invoke("set-secret", { name, value }), openExternal: (url) => ipcRenderer.invoke("open-external", { url }), quitApp: () => ipcRenderer.invoke("app-quit"), sessionsList: (opts) => ipcRenderer.invoke("sessions-list", typeof opts === "object" && opts !== null ? opts : { includeSubagent: !!opts }), sessionsDataDirInfo: () => ipcRenderer.invoke("sessions-data-dir-info"), sessionsDataDirSelect: () => ipcRenderer.invoke("sessions-data-dir-select"), sessionsDataDirReset: () => ipcRenderer.invoke("sessions-data-dir-reset"), sessionRead: (path) => ipcRenderer.invoke("session-read", { path }), sessionDeletePermanently: (path) => ipcRenderer.invoke("session-delete-permanently", { path }), sessionsClearAll: () => ipcRenderer.invoke("sessions-clear-all"), sessionExport: (item) => ipcRenderer.invoke("session-export", { item }), sessionsBackup: () => ipcRenderer.invoke("sessions-backup"), sessionsImport: () => ipcRenderer.invoke("sessions-import"), // —— 会话记忆 —— memoryStatus: () => ipcRenderer.invoke("memory-status"), memoryList: (opts) => ipcRenderer.invoke("memory-list", opts), memorySetEnabled: (enabled) => ipcRenderer.invoke("memory-set-enabled", { enabled }), memoryToggleProject: (cwd, enabled) => ipcRenderer.invoke("memory-toggle-project", { cwd, enabled }), memoryResummarize: (path) => ipcRenderer.invoke("memory-resummarize", { path }), memoryDelete: (id) => ipcRenderer.invoke("memory-delete", { id }), memoryOpenHandoff: (cwd) => ipcRenderer.invoke("memory-open-handoff", { cwd }), onMemoryChanged: (cb) => { const handler = () => cb(); ipcRenderer.on("memory-changed", handler); return () => ipcRenderer.removeListener("memory-changed", handler); }, providerSyncStatus: () => ipcRenderer.invoke("provider-sync-status"), providerSync: () => ipcRenderer.invoke("provider-sync"), onProviderSyncProgress: (cb) => { const handler = (_e, p) => cb(p); ipcRenderer.on("provider-sync-progress", handler); return () => ipcRenderer.removeListener("provider-sync-progress", handler); }, routerStatus: () => ipcRenderer.invoke("router-status"), routerDefaultConfig: () => ipcRenderer.invoke("router-default-config"), routerUpsertGroup: (group) => ipcRenderer.invoke("router-upsert-group", { group }), routerDeleteGroup: (id) => ipcRenderer.invoke("router-delete-group", { id }), routerSetActive: (id) => ipcRenderer.invoke("router-set-active", { id }), routerSetPort: (port) => ipcRenderer.invoke("router-set-port", { port }), routerStart: () => ipcRenderer.invoke("router-start"), routerStop: () => ipcRenderer.invoke("router-stop"), routerDisableCodex: () => ipcRenderer.invoke("router-disable-codex"), routerApplyCodex: () => ipcRenderer.invoke("router-apply-codex"), routerApplyDirect: (id) => ipcRenderer.invoke("router-apply-direct", { id }), routerApplyClaude: () => ipcRenderer.invoke("router-apply-claude"), routerRestoreClaude: () => ipcRenderer.invoke("router-restore-claude"), routerSnippet: () => ipcRenderer.invoke("router-snippet"), routerFetchModels: (baseUrl, key, groupId) => ipcRenderer.invoke("router-fetch-models", { baseUrl, key, groupId }), // —— 接入 Claude 桌面 App —— claudedeskStatus: () => ipcRenderer.invoke("claudedesk-status"), claudedeskApply: (groupId) => ipcRenderer.invoke("claudedesk-apply", { groupId }), claudedeskRestore: () => ipcRenderer.invoke("claudedesk-restore"), claudedeskSnippet: (groupId) => ipcRenderer.invoke("claudedesk-snippet", { groupId }), claudedeskExport: (groupId, format) => ipcRenderer.invoke("claudedesk-export", { groupId, format }), onRouterChanged: (cb) => { const handler = (_e, s) => cb(s); ipcRenderer.on("router-changed", handler); return () => ipcRenderer.removeListener("router-changed", handler); }, // —— 创意画布(中转执行层)—— canvasStatus: () => ipcRenderer.invoke("canvas-status"), canvasRun: (kind, params) => ipcRenderer.invoke("canvas-run", { kind, params }), canvasGroups: () => ipcRenderer.invoke("canvas-groups"), canvasModels: (groupId) => ipcRenderer.invoke("canvas-models", { groupId }), canvasWorkspaces: () => ipcRenderer.invoke("canvas-workspaces"), canvasWorkspaceCreate: (name) => ipcRenderer.invoke("canvas-workspace-create", { name }), canvasWorkspaceLoad: (id) => ipcRenderer.invoke("canvas-workspace-load", { id }), canvasWorkspaceRename: (id, name) => ipcRenderer.invoke("canvas-workspace-rename", { id, name }), canvasWorkspaceSave: (workspace) => ipcRenderer.invoke("canvas-workspace-save", { workspace }), canvasWorkspaceSaveNow: (workspace) => ipcRenderer.send("canvas-workspace-save-now", workspace), canvasMediaCache: (payload) => ipcRenderer.invoke("canvas-media-cache", payload || {}), canvasMediaRead: (payload) => ipcRenderer.invoke("canvas-media-read", payload || {}), // —— 多 Agent 员工团队生成 —— teamGenerate: (params) => ipcRenderer.invoke("team-generate", params || {}), teamPreview: (params) => ipcRenderer.invoke("team-preview", params || {}), teamPack: (params) => ipcRenderer.invoke("team-pack", params || {}), // —— 提示词提取(图片 → 反推生图提示词)—— promptGroups: () => ipcRenderer.invoke("prompt-groups"), promptModels: (groupId) => ipcRenderer.invoke("prompt-models", { groupId }), promptAnalyze: (params) => ipcRenderer.invoke("prompt-analyze", params || {}), onCanvasProgress: (cb) => { const h = (_e, p) => cb(p); ipcRenderer.on("canvas-progress", h); return () => ipcRenderer.removeListener("canvas-progress", h); }, // —— Codex 语音输入注入(CDP 连 Codex,注入麦克风按钮)—— voiceStatus: () => ipcRenderer.invoke("voice-status"), voiceConnect: (opts) => ipcRenderer.invoke("voice-connect", opts || {}), voiceDisconnect: () => ipcRenderer.invoke("voice-disconnect"), voiceRestartCodex: () => ipcRenderer.invoke("voice-restart-codex"), voiceSttInfo: () => ipcRenderer.invoke("voice-stt-info"), voiceProbeStt: () => ipcRenderer.invoke("voice-probe-stt"), onVoiceStatus: (cb) => { const h = (_e, s) => cb(s); ipcRenderer.on("voice-status", h); return () => ipcRenderer.removeListener("voice-status", h); }, // —— Token 用量监控(注入 Codex,复用 CDP 连接)—— tokenStatus: () => ipcRenderer.invoke("token-status"), tokenReset: () => ipcRenderer.invoke("token-reset"), // —— 全局 / 系统代理 —— proxyStatus: () => ipcRenderer.invoke("proxy-status"), proxyGetConfig: () => ipcRenderer.invoke("proxy-get-config"), proxySetConfig: (cfg) => ipcRenderer.invoke("proxy-set-config", cfg), proxyStart: (mode) => ipcRenderer.invoke("proxy-start", { mode }), proxyStop: () => ipcRenderer.invoke("proxy-stop"), proxyTest: () => ipcRenderer.invoke("proxy-test"), onProxyChanged: (cb) => { const handler = (_e, s) => cb(s); ipcRenderer.on("proxy-changed", handler); return () => ipcRenderer.removeListener("proxy-changed", handler); }, // —— 检测 / 强制清除本机 Codex —— codexDetect: () => ipcRenderer.invoke("codex-detect"), codexPurge: (paths) => ipcRenderer.invoke("codex-purge", { paths }), appVersion: () => ipcRenderer.invoke("app-version"), checkUpdate: () => ipcRenderer.invoke("check-update"), onUpdateStatus: (cb) => { const handler = (_e, s) => cb(s); ipcRenderer.on("update-status", handler); return () => ipcRenderer.removeListener("update-status", handler); }, onLog: (cb) => { const handler = (_e, msg) => cb(msg); ipcRenderer.on("log", handler); return () => ipcRenderer.removeListener("log", handler); }, });