IPC Protocol Dictionary
1. Channel Topology
flowchart TB R[Renderer] --> P[preload.ts] P -->|ipcRenderer.send/invoke| M[main/index.ts ipcMain] M -->|HTTP + internal token| B[backend routes]
2. Channel Dictionary
| Channel | IPC Type | Params | Return Schema | Main Handler Behavior |
|---|---|---|---|---|
app:close-window | send | none | none | Closes focused window or main window |
i18n:get-locale | invoke | none | Promise<string> | Returns current resolved locale |
i18n:set-locale | invoke | locale: string | Promise<string> | Resolves/persists in-memory locale and updates title |
app:get-runtime-user-name | invoke | none | Promise<string> | Returns OS username fallback chain |
app:get-version-info | invoke | none | Promise<{ appName: string; version: string; buildVersion: string; buildTime: string; commit: string; electron: string; chromium: string; node: string; v8: string; os: string }> | Returns About metadata including app version/build plus runtime technical information |
app:get-pending-launch-working-directory | invoke | none | Promise<string | null> | Returns current pending context-launch working directory parsed from CLI |
app:get-database-security-info | invoke | none | Promise<{ runtimeMode: 'development' | 'production'; resolverMode: 'development-fixed-key' | 'safe-storage' | 'master-password-fallback'; safeStorageAvailable: boolean; databasePath: string; securityConfigPath: string; hasEncryptedDbMasterKey: boolean; hasMasterPasswordHash: boolean; hasMasterPasswordSalt: boolean; hasMasterPasswordEnv: boolean; fallbackReady: boolean }> | Returns non-sensitive database encryption bootstrap diagnostics for Settings → Advanced |
app:launch-working-directory | event (main -> renderer) | cwd: string | none | Pushes context-launch working directory when a second instance is invoked |
app:menu-action | event (main -> renderer) | action: 'open-about' | 'open-settings' | 'new-tab' | 'close-current-tab' | 'close-right-tabs' | 'show-tab-switcher' | none | Dispatches validated app-menu commands from the macOS system menu to renderer tab/state handlers |
app:open-devtools | invoke | none | Promise<boolean> | Opens devtools for the current main window when available |
app:toggle-devtools | invoke | none | Promise<boolean> | Toggles detached DevTools for the current main window (open when closed, close when open) |
app:reload-webview | invoke | none | Promise<boolean> | Reloads the active renderer webContents and bypasses cache for deterministic debug refresh |
app:restart-backend-runtime | invoke | none | Promise<boolean> | Restarts backend runtime in-place during development without full app restart |
app:show-in-file-manager | invoke | targetPath?: string | Promise<boolean> | Opens file/folder in OS file manager |
app:open-external-url | invoke | targetUrl: string | Promise<boolean> | Opens trusted HTTP(S) URL with system default browser |
app:set-windows-system-menu-symbol-color | invoke | symbolColor: string | Promise<boolean> | Applies token-driven Windows title bar system-menu symbol color to current main window overlay |
app:import-private-key | invoke | none | Promise<{ canceled: boolean; content?: string }> | Opens native file picker and returns UTF-8 private key content when selected |
app:get-process-performance-stats | invoke | none | Promise<{ sampledAt: number; cpuPercent: number | null; mainProcessMemory: { rssBytes: number; heapTotalBytes: number; heapUsedBytes: number; externalBytes: number; arrayBuffersBytes: number }; rendererProcessMemory: { residentSetBytes: number; privateBytes: number; sharedBytes: number } | null; backendProcess: { pid: number; cpuPercent: number | null; memoryRssBytes: number | null } | null }> | Samples main process CPU + memory, resolves renderer process memory from active window, and includes backend child-process CPU/RSS memory for debug monitoring overlay |
app:export-main-heap-snapshot | invoke | none | Promise<{ ok: boolean; filePath?: string; message?: string }> | Writes a V8 heap snapshot for the main process into app user-data debug snapshot directory |
backend:test-ping | invoke | none | Promise<ApiTestPingResponse | ApiErrorResponse> | Calls backend health test endpoint |
backend:settings-get | invoke | none | Promise<ApiSettingsGetResponse | ApiErrorResponse> | GET persisted application settings |
backend:settings-update | invoke | payload: ApiSettingsUpdateRequest | Promise<ApiSettingsUpdateResponse | ApiErrorResponse> | PUT application settings snapshot |
backend:ssh-list-servers | invoke | none | Promise<ApiSshListServersResponse | ApiErrorResponse> | GET SSH server list |
backend:ssh-create-server | invoke | payload: ApiSshCreateServerRequest | Promise<ApiSshCreateServerResponse | ApiErrorResponse> | POST create SSH server |
backend:ssh-update-server | invoke | serverId: string, payload: ApiSshUpdateServerRequest | Promise<ApiSshUpdateServerResponse | ApiErrorResponse> | PUT update SSH server |
backend:ssh-get-server-credentials | invoke | serverId: string | Promise<ApiSshGetServerCredentialsResponse | ApiErrorResponse> | GET decrypted credentials |
backend:ssh-list-folders | invoke | none | Promise<ApiSshListFoldersResponse | ApiErrorResponse> | GET folder list |
backend:ssh-create-folder | invoke | payload: ApiSshCreateFolderRequest | Promise<ApiSshCreateFolderResponse | ApiErrorResponse> | POST create folder |
backend:ssh-update-folder | invoke | folderId: string, payload: ApiSshUpdateFolderRequest | Promise<ApiSshUpdateFolderResponse | ApiErrorResponse> | PUT update folder |
backend:ssh-list-tags | invoke | none | Promise<ApiSshListTagsResponse | ApiErrorResponse> | GET tag list |
backend:ssh-create-tag | invoke | payload: ApiSshCreateTagRequest | Promise<ApiSshCreateTagResponse | ApiErrorResponse> | POST create tag |
backend:ssh-list-keychains | invoke | none | Promise<ApiSshListKeychainsResponse | ApiErrorResponse> | GET keychain list |
backend:ssh-create-keychain | invoke | payload: ApiSshCreateKeychainRequest | Promise<ApiSshCreateKeychainResponse | ApiErrorResponse> | POST create keychain |
backend:ssh-update-keychain | invoke | keychainId: string, payload: ApiSshUpdateKeychainRequest | Promise<ApiSshUpdateKeychainResponse | ApiErrorResponse> | PUT update keychain |
backend:ssh-get-keychain-credentials | invoke | keychainId: string | Promise<ApiSshGetKeychainCredentialsResponse | ApiErrorResponse> | GET decrypted keychain credentials |
backend:ssh-create-session | invoke | payload: ApiSshCreateSessionRequest | Promise<ApiSshCreateSessionResponse | ApiSshCreateSessionHostVerificationRequiredResponse | ApiErrorResponse> | POST create SSH shell session |
backend:ssh-trust-fingerprint | invoke | payload: ApiSshTrustFingerprintRequest | Promise<ApiSshTrustFingerprintResponse | ApiErrorResponse> | POST trust host fingerprint |
backend:ssh-close-session | invoke | sessionId: string | Promise<{ success: boolean }> | DELETE SSH session |
backend:ssh-delete-server | invoke | serverId: string | Promise<{ success: boolean }> | DELETE SSH server |
backend:ssh-delete-folder | invoke | folderId: string | Promise<{ success: boolean }> | DELETE SSH folder |
backend:ssh-delete-keychain | invoke | keychainId: string | Promise<{ success: boolean }> | DELETE SSH keychain |
backend:local-terminal-list-profiles | invoke | none | Promise<ApiLocalTerminalListProfilesResponse | ApiErrorResponse> | GET local terminal profile list |
backend:local-terminal-create-session | invoke | payload: ApiLocalTerminalCreateSessionRequest | Promise<ApiLocalTerminalCreateSessionResponse | ApiErrorResponse> | POST local terminal session (Main may inject one-shot cwd from launch context) |
backend:local-terminal-close-session | invoke | sessionId: string | Promise<{ success: boolean }> | DELETE local terminal session |
3. Schema Sources
- API payload types come from
@cosmosh/api-contract, generated frompackages/api-contract/openapi/cosmosh.openapi.yaml. - Backend, Main IPC proxy, and renderer HTTP callers must use
API_PATHSand related generated contract exports from@cosmosh/api-contractinstead of hard-coded route strings.
3.1 SSH Visual Metadata Fields
The following SSH entity payloads now include visual metadata for persistent icon/color customization:
ApiSshCreateServerRequest/ApiSshUpdateServerRequest: optionaliconKey, optionalcolorKey.ApiSshCreateFolderRequest/ApiSshUpdateFolderRequest: optionaliconKey, optionalcolorKey.ApiSshListServersResponse: each server item includesiconKeyandcolorKey.ApiSshListFoldersResponse: each folder item includesiconKeyandcolorKey.
colorKey is constrained to the predefined palette enum in the API contract.
SSH security policy fields in current contract:
ApiSshCreateServerRequest/ApiSshUpdateServerRequest:strictHostKeyboolean.ApiSshListServersResponse: each server item includes persistedstrictHostKey.ApiSshCreateSessionRequest: optionalstrictHostKeyoverride used for one session attempt.
3.2 Terminal WebSocket Contract (Renderer ↔ Backend)
Although terminal stream messages are not Electron IPC channels, they are part of the same cross-process contract surface and must be versioned together.
- Client to server (
/ws/ssh/{sessionId}and/ws/local-terminal/{sessionId}):input,resize,ping,close,history-deletecompletion-requestwithrequestId,linePrefix,cursorIndex, optionalworkingDirectoryHint, optionallimit, optionalfuzzyMatch, optional source filters (includeHistory,includeBuiltInCommands,includePathSuggestions,includePasswordSuggestions), andtrigger(typingormanual)
- Server to client:
ready,output,telemetry,history,pong,error,exitcompletion-responsewithrequestId,replacePrefixLength, and ranked completionitems
Completion item contract notes:
items[].sourceincludeshistory,inshellisense, and runtime-computedruntime.items[].kindincludes existing command-spec/history categories plus runtime categories (path,secret).- Runtime categories are used for path candidates and interactive secret-fill actions while preserving the same
completion-responseenvelope.
Current implementation note:
- Completion messages are handled in
SshSessionServiceandLocalTerminalSessionServicevia shared normalization interminal/shared.tsand shared ranking engine interminal/completion/engine.ts.
4. Change Rules
When adding/modifying a channel, update in one commit:
packages/main/src/preload.tspackages/main/src/index.tspackages/renderer/src/vite-env.d.ts- relevant renderer transport/service wrappers
- this file (
docs/developer/core/ipc-protocol.md)
5. Channel Addition Template
Use this checklist when introducing a new channel:
- Channel name:
domain:action-name - IPC type:
invokeorsend - Params schema: explicit type in bridge and renderer declarations
- Return schema: success and error shape
- Main behavior: backend proxy or privileged local action
- Security notes: token/header handling, permission boundary, exposure limits
- Docs sync: update EN + ZH protocol pages in same change set