2026-07-15 18:01:56 +08:00
|
|
|
// 契约边界(已冻结):把主进程能力安全暴露给前端 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: () => ipcRenderer.invoke("skill-installed"),
|
|
|
|
|
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: () => ipcRenderer.invoke("plugin-installed"),
|
|
|
|
|
pluginUninstall: (rel) => ipcRenderer.invoke("plugin-uninstall", { rel }),
|
|
|
|
|
pluginMigrate: () => ipcRenderer.invoke("plugin-migrate"),
|
|
|
|
|
// —— 热更新 ——
|
|
|
|
|
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 }),
|
|
|
|
|
sessionRead: (path) => ipcRenderer.invoke("session-read", { path }),
|
|
|
|
|
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"),
|
|
|
|
|
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"),
|
|
|
|
|
routerApplyCodex: () => ipcRenderer.invoke("router-apply-codex"),
|
|
|
|
|
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 }),
|
|
|
|
|
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 }),
|
|
|
|
|
onCanvasProgress: (cb) => {
|
|
|
|
|
const h = (_e, p) => cb(p);
|
|
|
|
|
ipcRenderer.on("canvas-progress", h);
|
|
|
|
|
return () => ipcRenderer.removeListener("canvas-progress", h);
|
|
|
|
|
},
|
2026-07-16 19:16:45 +08:00
|
|
|
// —— Codex 语音输入注入(CDP 连 Codex,注入麦克风按钮)——
|
|
|
|
|
voiceStatus: () => ipcRenderer.invoke("voice-status"),
|
|
|
|
|
voiceConnect: (opts) => ipcRenderer.invoke("voice-connect", opts || {}),
|
|
|
|
|
voiceDisconnect: () => ipcRenderer.invoke("voice-disconnect"),
|
|
|
|
|
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);
|
|
|
|
|
},
|
2026-07-15 18:01:56 +08:00
|
|
|
// —— 全局 / 系统代理 ——
|
|
|
|
|
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);
|
|
|
|
|
},
|
|
|
|
|
});
|