mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-08-24 07:43:28 +00:00
## Summary - add project folder, terminal, and explicit editor actions to the command palette and native File menus - replace the Files-row copy button with desktop context actions while preserving internal file navigation and web/remote copy fallback - resolve trusted workspace roots through the authenticated local server and enforce canonical path containment in Electron and Tauri - use safe platform launch policies, including Windows Open/Edit/Open With handling and executable rejection on Unix - localize all new UI actions across supported locales ## Validation - npm run typecheck - npm run test:native --workspace @neuralnomads/codenomad-electron-app (122 passed) - cargo test (86 passed) - npm run build - git diff --check - independent security, platform, and UX reviews: zero findings Closes #570
66 lines
2.9 KiB
JavaScript
66 lines
2.9 KiB
JavaScript
const { contextBridge, ipcRenderer, webUtils } = require("electron")
|
|
|
|
function resolveWindowContext() {
|
|
const prefix = "--codenomad-window-context="
|
|
const arg = process.argv.find((value) => typeof value === "string" && value.startsWith(prefix))
|
|
const context = arg ? arg.slice(prefix.length) : "local"
|
|
return context === "remote" ? "remote" : "local"
|
|
}
|
|
|
|
function resolveRuntimeHost(windowContext) {
|
|
return "electron"
|
|
}
|
|
|
|
const windowContext = resolveWindowContext()
|
|
|
|
const localElectronAPI = {
|
|
onCliStatus: (callback) => {
|
|
ipcRenderer.on("cli:status", (_, data) => callback(data))
|
|
return () => ipcRenderer.removeAllListeners("cli:status")
|
|
},
|
|
onCliError: (callback) => {
|
|
ipcRenderer.on("cli:error", (_, data) => callback(data))
|
|
return () => ipcRenderer.removeAllListeners("cli:error")
|
|
},
|
|
getCliStatus: () => ipcRenderer.invoke("cli:getStatus"),
|
|
restartCli: () => ipcRenderer.invoke("cli:restart"),
|
|
openDialog: (options) => ipcRenderer.invoke("dialog:open", options),
|
|
getDirectoryPaths: (paths) => ipcRenderer.invoke("filesystem:getDirectoryPaths", paths),
|
|
openWorkspaceTarget: (payload) => ipcRenderer.invoke("workspace:openTarget", payload),
|
|
setWorkspaceMenuEnabled: (enabled) => ipcRenderer.invoke("workspace:setMenuEnabled", Boolean(enabled)),
|
|
onMenuAction: (callback) => {
|
|
const handler = (_event, action) => callback(action)
|
|
ipcRenderer.on("menu:action", handler)
|
|
return () => ipcRenderer.removeListener("menu:action", handler)
|
|
},
|
|
getPathForFile: (file) => {
|
|
try {
|
|
return webUtils.getPathForFile(file)
|
|
} catch {
|
|
return null
|
|
}
|
|
},
|
|
requestMicrophoneAccess: () => ipcRenderer.invoke("media:requestMicrophoneAccess"),
|
|
setWakeLock: (enabled) => ipcRenderer.invoke("power:setWakeLock", Boolean(enabled)),
|
|
showNotification: (payload) => ipcRenderer.invoke("notifications:show", payload),
|
|
openRemoteWindow: (payload) => ipcRenderer.invoke("remote:openWindow", payload),
|
|
claimClientStateAccess: (token) => ipcRenderer.invoke("client-state:claimAccess", token),
|
|
loadClientState: (token) => ipcRenderer.invoke("client-state:load", token),
|
|
saveClientState: (token, snapshot) => ipcRenderer.invoke("client-state:save", token, snapshot),
|
|
setClientStateRestoreEnabled: (token, enabled) =>
|
|
ipcRenderer.invoke("client-state:setRestoreEnabled", token, Boolean(enabled)),
|
|
clearClientState: (token) => ipcRenderer.invoke("client-state:clear", token),
|
|
}
|
|
|
|
const remoteElectronAPI = {
|
|
requestMicrophoneAccess: localElectronAPI.requestMicrophoneAccess,
|
|
setWakeLock: localElectronAPI.setWakeLock,
|
|
showNotification: localElectronAPI.showNotification,
|
|
}
|
|
|
|
contextBridge.exposeInMainWorld(
|
|
"electronAPI",
|
|
windowContext === "local" ? localElectronAPI : remoteElectronAPI,
|
|
)
|
|
contextBridge.exposeInMainWorld("__CODENOMAD_WINDOW_CONTEXT__", windowContext)
|
|
contextBridge.exposeInMainWorld("__CODENOMAD_RUNTIME_HOST__", resolveRuntimeHost(windowContext))
|