Skip to content

IPC 协议字典

1. Channel 拓扑

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 字典

ChannelIPC TypeParamsReturn SchemaMain Handler Behavior
app:close-windowsendnonenone请求关闭当前聚焦窗口或主窗口;主窗口关闭守卫会先检查 backend SSH/SFTP 活动状态再允许销毁
app:close-confirmation-requestMain-to-renderer event{ requestId: string }none请求使用共享 renderer 对话框显示关闭警告;preload 校验不透明 ID,并在 React listener 挂载前暂存一个提前到达的请求
app:close-confirmation-responsesend{ requestId: string, confirmed: boolean }none仅解析由当前发送 webContents 持有且不透明 request ID 匹配的进行中关闭决策
i18n:get-localeinvokenonePromise<string>Returns current resolved locale
i18n:set-localeinvokelocale: stringPromise<string>Resolves/persists in-memory locale and updates title
app:get-runtime-user-nameinvokenonePromise<string>Returns OS username fallback chain
app:get-version-infoinvokenonePromise<{ appName: string; version: string; buildVersion: string; buildTime: string; commit: string; electron: string; chromium: string; node: string; v8: string; os: string }>为关于页返回应用名称、版本号、构建时间与运行时技术信息
app:get-pending-launch-working-directoryinvokenonePromise<string | null>返回当前待消费的上下文启动工作目录(来自 CLI 参数)
app:get-downloads-pathinvokenonePromise<string>返回系统下载目录,供本地保存默认路径使用
app:create-sftp-temporary-fileinvokefileName: stringPromise<string>在 Cosmosh SFTP 临时根目录下创建唯一的本地目标路径,供 backend 下载与打开流程使用
app:create-sftp-downloads-fileinvokefileName: stringPromise<string>在系统 Downloads 目录下为发起请求的 renderer 授权一个精确的单次下载目标
app:select-sftp-upload-filesinvokenonePromise<{ canceled: boolean; files: Array<{ name: string; localPath: string; size: number; modifiedAt: string }> }>打开原生多文件选择器,并将所选普通文件复制到受控 SFTP 临时根目录下的隔离目录
app:stage-sftp-dropped-upload-filesinvokeentries: Array<{ name: string; localPath?: string }>Promise<{ canceled: false; files: Array<{ name: string; localPath: string; size: number; modifiedAt: string }>; rejectedEntries?: Array<{ name: string; reason: 'directory-unsupported' | 'not-file' | 'path-unavailable' | 'unreadable' }> }>暂存 preload 已解析的、拖放到 SFTP 目录目标上的本地文件,并在不向 renderer 暴露任意路径暂存能力的前提下报告不支持的文件夹/非文件项
app:cleanup-sftp-temporary-filesinvokelocalPaths: string[]Promise<boolean>尽力删除经过校验的上传暂存文件及其已清空的隔离临时目录
app:open-sftp-temporary-fileinvokelocalPath: stringPromise<boolean>使用系统默认应用打开 Cosmosh SFTP 临时根目录下的既有文件
app:read-sftp-temporary-image-previewinvokelocalPath: stringPromise<string>校验 Cosmosh SFTP 临时根目录下的既有图片文件,并返回有大小上限的 data URL 供 renderer 图片预览使用
app:start-sftp-temporary-file-watchinvokelocalPath: stringPromise<string>为 Cosmosh SFTP 临时根目录下的既有文件启动防抖监听,并返回 watch id
app:stop-sftp-temporary-file-watchinvokewatchId: stringPromise<boolean>停止此前创建的 SFTP 临时文件监听
app:show-sftp-open-with-dialoginvokelocalPath: stringPromise<boolean>仅 Windows:校验临时文件路径,并通过 shell openas verb 打开系统“打开方式”选择器
app:list-sftp-open-with-applicationsinvokelocalPath: stringPromise<Array<{ id: string; name: string; path: string; bundleIdentifier?: string; iconDataUrl?: string }>>仅 macOS:校验临时文件路径,并返回 NSWorkspace 判定可打开该文件的应用列表
app:open-sftp-file-with-applicationinvokelocalPath: string, applicationPath: stringPromise<boolean>仅 macOS:校验临时文件与所选应用属于可用应用列表后,使用该应用打开文件
app:sftp-temporary-file-changedevent (main -> renderer){ watchId: string; localPath: string; size: number; modifiedAt: string }none向拥有该监听的 renderer webContents 推送一次防抖后的 SFTP 临时文件变更事件
app:get-database-security-infoinvokenonePromise<{ 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 }>为设置 → 高级页返回非敏感的数据库加密引导诊断信息
app:resolve-system-proxyinvoke{ host: string; port: number }Promise<{ proxyRules: string }>校验一个 SSH 服务器目标,并为 https://host:port/ 解析 Chromium 系统/PAC 代理规则
app:launch-working-directoryevent (main -> renderer)cwd: stringnone当第二实例触发时,向渲染层推送上下文启动工作目录
app:menu-actionevent (main -> renderer)action: 'open-about' | 'open-settings' | 'new-tab' | 'close-current-tab' | 'close-right-tabs' | 'show-tab-switcher'none将 macOS 系统菜单触发的应用菜单命令以受控枚举形式分发到渲染层标签页/状态处理器
app:open-devtoolsinvokenonePromise<boolean>为当前主窗口打开 DevTools(窗口可用时)
app:toggle-devtoolsinvokenonePromise<boolean>切换当前主窗口的分离式 DevTools(已打开则关闭,已关闭则打开)
app:reload-webviewinvokenonePromise<boolean>重新加载当前活动 renderer webContents,并忽略缓存以保证调试刷新可预测
app:restart-backend-runtimeinvokenonePromise<boolean>在开发环境中原位重启 backend 运行时,无需重启整个应用
app:show-in-file-managerinvoketargetPath?: stringPromise<boolean>Opens file/folder in OS file manager
app:open-external-urlinvoketargetUrl: stringPromise<boolean>使用系统默认浏览器打开受信任的 HTTP(S) 链接
app:set-windows-system-menu-symbol-colorinvokesymbolColor: stringPromise<boolean>将 token 驱动的 Windows 标题栏系统菜单符号色应用到当前主窗口 overlay
app:show-save-file-dialoginvokedefaultPath?: stringPromise<{ canceled: boolean; filePath?: string }>打开原生保存对话框,并为发起请求的 renderer 授权所选路径执行一次 SFTP 下载
app:import-private-keyinvokenonePromise<{ canceled: boolean; fileName?: string; content?: string }>调起系统文件选择器并在选择后返回文件名与 UTF-8 私钥内容
app:get-process-performance-statsinvokenonePromise<{ 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 }>为调试浮层采样主进程 CPU/内存,基于当前活动窗口获取渲染进程内存,并补充 backend 子进程 CPU/RSS 内存数据
app:export-main-heap-snapshotinvokenonePromise<{ ok: boolean; filePath?: string; message?: string }>将主进程 V8 堆快照写入应用 user-data 下的 debug 快照目录
debug:backend-request-trace-listinvokenonePromise<BackendRequestTrace[]>返回已保留的脱敏 backend 请求镜像列表,并让该 renderer webContents 订阅后续 trace event;未启用请求追踪时返回空列表
debug:backend-request-trace-clearinvokenonePromise<boolean>清空开发态请求镜像 ring buffer
debug:backend-request-trace-eventevent (main -> renderer)BackendRequestTracenone向已订阅的 renderer webContents 推送一条已完成且脱敏的 backend proxy 请求镜像
backend:test-pinginvokenonePromise<ApiTestPingResponse | ApiErrorResponse>Calls backend health test endpoint
backend:settings-getinvokenonePromise<ApiSettingsGetResponse | ApiErrorResponse>GET 已持久化设置
backend:settings-updateinvokepayload: ApiSettingsUpdateRequestPromise<ApiSettingsUpdateResponse | ApiErrorResponse>PUT 设置快照
backend:audit-list-eventsinvokequery?: ApiAuditEventListQueryPromise<ApiAuditEventListResponse | ApiErrorResponse>GET 审计事件列表(支持过滤与分页)
backend:audit-get-event-by-idinvokeeventId: stringPromise<ApiAuditEventDetailResponse | ApiErrorResponse>GET 单条审计事件详情
backend:ssh-list-serversinvokenonePromise<ApiSshListServersResponse | ApiErrorResponse>GET SSH server list
backend:ssh-create-serverinvokepayload: ApiSshCreateServerRequestPromise<ApiSshCreateServerResponse | ApiErrorResponse>POST create SSH server
backend:ssh-update-serverinvokeserverId: string, payload: ApiSshUpdateServerRequestPromise<ApiSshUpdateServerResponse | ApiErrorResponse>PUT update SSH server
backend:ssh-get-server-credentialsinvokeserverId: stringPromise<ApiSshGetServerCredentialsResponse | ApiErrorResponse>GET decrypted credentials
backend:ssh-list-foldersinvokenonePromise<ApiSshListFoldersResponse | ApiErrorResponse>GET folder list
backend:ssh-create-folderinvokepayload: ApiSshCreateFolderRequestPromise<ApiSshCreateFolderResponse | ApiErrorResponse>POST create folder
backend:ssh-update-folderinvokefolderId: string, payload: ApiSshUpdateFolderRequestPromise<ApiSshUpdateFolderResponse | ApiErrorResponse>PUT update folder
backend:ssh-list-tagsinvokenonePromise<ApiSshListTagsResponse | ApiErrorResponse>GET tag list
backend:ssh-create-taginvokepayload: ApiSshCreateTagRequestPromise<ApiSshCreateTagResponse | ApiErrorResponse>POST create tag
backend:ssh-list-keychainsinvokenonePromise<ApiSshListKeychainsResponse | ApiErrorResponse>GET 钥匙链列表
backend:ssh-create-keychaininvokepayload: ApiSshCreateKeychainRequestPromise<ApiSshCreateKeychainResponse | ApiErrorResponse>POST 创建钥匙链
backend:ssh-update-keychaininvokekeychainId: string, payload: ApiSshUpdateKeychainRequestPromise<ApiSshUpdateKeychainResponse | ApiErrorResponse>PUT 更新钥匙链
backend:ssh-get-keychain-credentialsinvokekeychainId: stringPromise<ApiSshGetKeychainCredentialsResponse | ApiErrorResponse>GET 解密后的钥匙链凭据
backend:ssh-create-sessioninvokepayload: ApiSshCreateSessionRequestPromise<ApiSshCreateSessionResponse | ApiSshCreateSessionHostVerificationRequiredResponse | ApiErrorResponse>POST create SSH shell session
backend:ssh-trust-fingerprintinvokepayload: ApiSshTrustFingerprintRequestPromise<ApiSshTrustFingerprintResponse | ApiErrorResponse>POST trust host fingerprint
backend:ssh-close-sessioninvokesessionId: stringPromise<{ success: boolean }>DELETE SSH session
backend:ssh-delete-serverinvokeserverId: stringPromise<{ success: boolean }>DELETE SSH server
backend:ssh-delete-folderinvokefolderId: stringPromise<{ success: boolean }>DELETE SSH folder
backend:ssh-delete-keychaininvokekeychainId: stringPromise<{ success: boolean }>DELETE SSH 钥匙链
backend:port-forward-list-rulesinvokenonePromise<ApiPortForwardListRulesResponse | ApiErrorResponse>GET 已持久化的 SSH 端口转发规则,并合并内存运行状态
backend:port-forward-create-ruleinvokepayload: ApiPortForwardCreateRuleRequestPromise<ApiPortForwardCreateRuleResponse | ApiErrorResponse>POST 创建一条 stopped 端口转发规则
backend:port-forward-update-ruleinvokeruleId: string, payload: ApiPortForwardUpdateRuleRequestPromise<ApiPortForwardUpdateRuleResponse | ApiErrorResponse>PUT 更新一条 stopped 端口转发规则
backend:port-forward-start-ruleinvokeruleId: string, payload: ApiPortForwardStartRuleRequestPromise<ApiPortForwardStartRuleResponse | ApiErrorResponse>POST 启动一条规则,并可携带临时系统代理规则;可能返回共享 SSH_HOST_UNTRUSTED payload 供指纹信任后重试
backend:port-forward-stop-ruleinvokeruleId: stringPromise<ApiPortForwardStopRuleResponse | ApiErrorResponse>POST 停止一条活动规则;已停止规则由 backend 幂等处理
backend:port-forward-delete-ruleinvokeruleId: stringPromise<{ success: boolean }>DELETE 一条 stopped 端口转发规则
backend:sftp-create-sessioninvokepayload: ApiSftpCreateSessionRequestPromise<ApiSftpCreateSessionResponse | ApiSftpCreateSessionHostVerificationRequiredResponse | ApiErrorResponse>POST 创建 SFTP 文件系统会话
backend:sftp-list-directoryinvokesessionId: string, query?: ApiSftpListDirectoryQueryPromise<ApiSftpListDirectoryResponse | ApiErrorResponse>GET 单个 SFTP 目录列表
backend:sftp-get-entry-detailsinvokesessionId: string, payload: ApiSftpEntryDetailsRequestPromise<ApiSftpEntryDetailsResponse | ApiErrorResponse>POST 获取已选 SFTP 条目的非递归元数据
backend:sftp-read-fileinvokesessionId: string, query: ApiSftpReadFileQueryPromise<ApiSftpReadFileResponse | ApiErrorResponse>GET 当前 SFTP 会话内有上限的 UTF-8 文件预览
backend:sftp-write-fileinvokesessionId: string, payload: ApiSftpWriteFileRequestPromise<ApiSftpWriteFileResponse | ApiErrorResponse>POST 经过远程 size/mtime 冲突检查后,将可编辑 UTF-8 SFTP 预览内容保存回一个远程普通文件;远程冲突返回 SFTP_UPLOAD_CONFLICT
backend:sftp-download-fileinvokesessionId: string, payload: ApiSftpDownloadFileRequestPromise<ApiSftpDownloadFileResponse | ApiErrorResponse>POST 仅将一个远程普通 SFTP 文件流式写入 app utility IPC 为该 renderer 所有者授权的精确路径
backend:sftp-upload-fileinvokesessionId: string, payload: ApiSftpUploadFileRequestPromise<ApiSftpUploadFileResponse | ApiErrorResponse>POST 将一个受控本地临时文件流式写入新的远程路径,或在快照/显式覆盖确认后替换既有普通文件;冲突返回 SFTP_UPLOAD_CONFLICT
backend:sftp-get-transfer-progressinvoketransferId: stringPromise<ApiSftpTransferProgressResponse | ApiErrorResponse>GET 一个活动或近期完成的 SFTP 传输的字节进度、滚动速度、状态与可选失败原因
backend:sftp-create-directoryinvokesessionId: string, payload: ApiSftpCreateDirectoryRequestPromise<ApiSftpCreateDirectoryResponse | ApiErrorResponse>POST 创建远程 SFTP 目录
backend:sftp-create-fileinvokesessionId: string, payload: ApiSftpCreateFileRequestPromise<ApiSftpCreateFileResponse | ApiErrorResponse>POST 创建远程 SFTP 空文件
backend:sftp-rename-entryinvokesessionId: string, payload: ApiSftpRenameRequestPromise<ApiSftpRenameResponse | ApiErrorResponse>POST 重命名或移动远程 SFTP 条目
backend:sftp-copy-entryinvokesessionId: string, payload: ApiSftpCopyRequestPromise<ApiSftpCopyResponse | ApiErrorResponse>POST 复制远程 SFTP 文件或目录树
backend:sftp-delete-entryinvokesessionId: string, payload: ApiSftpDeleteRequestPromise<ApiSftpDeleteResponse | ApiErrorResponse>POST 删除远程 SFTP 文件、符号链接或目录树
backend:sftp-batch-operationinvokesessionId: string, payload: ApiSftpBatchOperationRequestPromise<ApiSftpBatchOperationResponse | ApiErrorResponse>POST 对多个 SFTP 条目执行有序批量复制、移动、创建链接或删除
backend:sftp-start-taskinvokesessionId: string, payload: ApiSftpStartTaskRequestPromise<ApiSftpStartTaskResponse | ApiErrorResponse>POST 启动一个异步 SFTP 任务;下载任务转发前必须消费精确匹配 owner/path/transferId 的授权
backend:sftp-list-tasksinvokesessionId: stringPromise<ApiSftpListTasksResponse | ApiErrorResponse>GET 保留的任务快照,并释放属于调用 renderer 的终态下载授权租约
backend:sftp-get-taskinvokesessionId: string, taskId: stringPromise<ApiSftpGetTaskResponse | ApiErrorResponse>使用任务接纳时的 session id 获取一个保留快照;观察到下载终态时释放绑定 owner 的授权租约
backend:sftp-get-archive-capabilitiesinvokesessionId: stringPromise<ApiSftpArchiveCapabilitiesResponse | ApiErrorResponse>GET 获取并缓存一个 SFTP 会话的固定远端归档工具能力矩阵
backend:sftp-start-archive-operationinvokesessionId: string, payload: ApiSftpArchiveOperationRequestPromise<ApiSftpArchiveOperationAcceptedResponse | ApiErrorResponse>POST 提交结构化压缩或解压请求;Main 不接受也不构造命令文本
backend:sftp-get-archive-operationinvokesessionId: string, operationId: stringPromise<ApiSftpArchiveOperationStatusResponse | ApiErrorResponse>GET 获取归档任务的保留状态、具名阶段(包括解压后的verifying)、冲突摘要、取消状态和稳定终态结果
backend:sftp-resolve-archive-conflictinvokesessionId: string, operationId: string, payload: ApiSftpArchiveConflictResolutionRequestPromise<ApiSftpArchiveConflictResolutionResponse | ApiErrorResponse>POST 为暂存解压冲突提交任务级overwritekeep-bothcancel决定
backend:sftp-cancel-archive-operationinvokesessionId: string, operationId: stringPromise<ApiSftpArchiveCancelResponse | ApiErrorResponse>DELETE 请求有界取消;通过归档任务轮询观察最终状态
backend:sftp-close-sessioninvokesessionId: stringPromise<{ success: boolean }>DELETE SFTP 会话
backend:local-terminal-list-profilesinvokenonePromise<ApiLocalTerminalListProfilesResponse | ApiErrorResponse>GET local terminal profile list
backend:local-terminal-create-sessioninvokepayload: ApiLocalTerminalCreateSessionRequestPromise<ApiLocalTerminalCreateSessionResponse | ApiErrorResponse>POST 本地终端会话(Main 可能注入一次性 cwd 上下文)
backend:local-terminal-close-sessioninvokesessionId: stringPromise<{ success: boolean }>DELETE local terminal session

3. Schema 来源

  • API payload 类型来自 @cosmosh/api-contract,并由 packages/api-contract/openapi/cosmosh.openapi.yaml 生成。
  • Backend、Main IPC 代理与 renderer HTTP 调用端必须通过 @cosmosh/api-contract 中生成的 API_PATHS 及相关合同导出访问 API,不允许硬编码路由字符串。
  • 归档 IPC 只接受生成的结构化路径、枚举和冲突决定。远端命令文本、flag、工具输出与暂存路径绝不跨越 preload 边界。
  • 未由 OpenAPI 生成的 IPC-only payload(包括 AppMenuActionSftpOpenWithApplicationSftpTemporaryFileWatchChangeBackendRequestTrace)定义在 packages/api-contract/src/ipc.ts,供 main、preload 与 renderer 类型声明共同消费。
  • 终端 WebSocket payload 与远端增强协议常量定义在 packages/api-contract/src/terminal-protocol.ts;backend 与 renderer 直接导入其中的 discriminated union。
  • BackendRequestTrace 仅用于开发诊断。它会在未打包开发运行中由 main-process backend proxy 填充;生产包不会采集 trace,也不会加载 DevTools extension。

3.1 SSH 视觉元数据字段

以下 SSH 实体相关载荷已包含用于持久化图标/配色自定义的视觉字段:

  • ApiSshCreateServerRequest / ApiSshUpdateServerRequest:可选 iconKey、可选 colorKey
  • ApiSshCreateFolderRequest / ApiSshUpdateFolderRequest:可选 iconKey、可选 colorKey
  • ApiSshListServersResponse:每个服务器条目包含 iconKeycolorKey
  • ApiSshListFoldersResponse:每个文件夹条目包含 iconKeycolorKey

colorKey 受 API 契约中的预设配色枚举约束。

当前 SSH 安全策略相关字段:

  • ApiSshCreateServerRequest / ApiSshUpdateServerRequest:主机/transport 与 renderer 策略字段包括 strictHostKeyenableSshCompressionremoteEnhancementsEnableddisableCharacterWidthCompatibilityModeterminalClipboardAccess 与 proxy policy。
  • ApiSshListServersResponse:每个 server 条目都必须包含持久化的 strictHostKeyenableSshCompressionremoteEnhancementsEnableddisableCharacterWidthCompatibilityModeterminalClipboardAccessproxyMode;响应缺少策略时,消费端不得通过本地默认值 fail open。
  • ApiSshCreateSessionRequest:可选 strictHostKeyenableSshCompressionremoteEnhancementsEnabled 会把单次尝试绑定到已解析快照。远端增强请求字段只能进一步关闭;最终权限为当前全局设置、持久化服务器字段与 request !== false
  • 字符宽度兼容模式不会传入 SSH session create 或终端 WS 消息;renderer 会在创建 xterm 实例时应用该规则。

3.2 SSH 端口转发契约

端口转发 payload 由 OpenAPI 源生成,并被 backend、main、preload 与 renderer wrapper 共同消费:

  • ApiPortForwardListRulesResponse
  • ApiPortForwardCreateRuleRequest / ApiPortForwardCreateRuleResponse
  • ApiPortForwardUpdateRuleRequest / ApiPortForwardUpdateRuleResponse
  • ApiPortForwardStartRuleResponse
  • ApiPortForwardStopRuleResponse

规则类型为 localremotedynamic

类型专属字段:

  • Local:localBindHostlocalBindPorttargetHosttargetPort
  • Remote:remoteBindHostremoteBindPorttargetHosttargetPort
  • Dynamic:localBindHostlocalBindPort

运行状态通过 runtime.status 返回,但不会持久化。Start 可能返回 SSH_HOST_UNTRUSTED;renderer 必须先通过 backend:ssh-trust-fingerprint 信任指纹,然后再重试。

3.3 SFTP 批量操作契约

SFTP batch payload 由 OpenAPI 生成,并由 renderer、main IPC proxy 与 backend routes 原样共用。

  • ApiSftpBatchOperationRequest.operation 可取 copymovelinkdelete
  • targetDirectoryPathcopymovelink 必填;对 delete 会被忽略。
  • link 会在目标目录中创建指向源远程绝对路径的绝对符号链接。目标名称使用源 basename,并沿用复制操作的冲突后缀策略。
  • 响应形状保持为 ApiSftpBatchOperationResponse:按顺序返回每个条目的结果、completed/failed/skipped 计数、fail-fast 执行,并且不回滚已经完成的条目。

3.4 终端 WebSocket 契约(Renderer ↔ Backend)

终端流式消息虽然不属于 Electron IPC channel,但同样属于跨进程契约面。terminal-protocol.ts 是唯一来源,当前远端 helper 协议版本为 2。

  • 客户端到服务端(/ws/ssh/{sessionId}/ws/local-terminal/{sessionId}):
    • inputresizepingclosehistory-delete
    • completion-request,包含 requestIdlinePrefixcursorIndex、可选 workingDirectoryHint、可选 limit、可选 fuzzyMatch、可选来源过滤字段(includeHistoryincludeBuiltInCommandsincludePathSuggestionsincludePasswordSuggestions)、triggertypingmanual
  • 服务端到客户端:
    • readyoutputtelemetryhistorypongerrorexit
    • completion-response,包含 requestIdreplacePrefixLength 与排序后的候选 items
    • bootstrap-status,用于侧通道 Remote Bootstrap 安装/探测状态
    • remote-enhancement-runtime-status,包含 backend 持有的状态(pendingactivedisabled),以及可选 helperVersionprotocolVersioncapabilitiescodemessage
    • remote-shell-event,用于已安装 helper 通过 OSC 777 发出的运行期 shell 状态;每条事件都必须包含 helperVersion、整数 protocolVersioncapabilitiesshelleventtimestamp

远端 shell event union 规则:

  • cwd 必须包含解码后的绝对 cwd,并声明 cwd capability。
  • command-startforeground-command 必须包含清洗后的 commandcommandIdcommand-end 还必须包含整数 exitCodedurationMs
  • line-state 必须包含 lineLengthcursorIndexpromptGeneration,不携带输入文本,目前仅由 Zsh 声明。
  • Sh/Ash 只声明 cwdprompt-ready。事件名与必填字段不符合交互 shell 打开前的精确 capability 契约时一律拒绝。

补全候选契约说明:

  • items[].source 目前包含 historyinshellisense 与运行时计算来源 runtime
  • items[].kind 在原有命令规范/历史分类之外,新增运行时分类(pathsecret)。
  • 运行时分类用于路径候选与交互式密钥填充动作,但仍复用相同的 completion-response 外层结构。

当前实现说明:

  • 补全消息在 SshSessionServiceLocalTerminalSessionService 中处理,输入规范化由 terminal/shared.ts 统一,排序引擎由 terminal/completion/engine.ts 共享。
  • remote-enhancement-runtime-statusremote-shell-event 仅用于 SSH session,不会出现在 local-terminal session。交互 shell 打开前的 Bootstrap ensure 成功后,运行时以 pending 开始;10 秒内到达且匹配的 integration-ready 会切换为 active。Ensure 失败、BOOTSTRAP_ENSURE_TIMEOUTHELPER_HANDSHAKE_TIMEOUT 或 live 契约不匹配都会切换为 disabled。Renderer 会把最新运行状态与有界事件历史分别保存,并且只能将其用于诊断,不得据此重建 backend helper 状态。
  • remote-shell-event 不得承载密码、secret、完整终端输出、完整命令行、line-buffer 内容或任意大数据。Helper 的动态 cwd/command 字段在 OSC JSON envelope 内使用规范 Base64,解码并校验后才会转发。Backend 将解码后的 OSC payload 限制在 8 KiB,剥离 Cosmosh OSC,并原样流式透传非 Cosmosh OSC。
  • Renderer 会把完整 server message union 路由到来源 pane 的 runtime/reducer。补全响应、密码提示、状态、telemetry、错误、退出、调试事件、重连与命令 marker 都不得隐式回退到 primary/active pane 状态。

3.5 Main 持有的活动连接契约

关闭守卫将活动状态权威性保留在带鉴权的 Main 到 Backend HTTP 调用中,只向 renderer 暴露窄化的确认握手:

  • GET /api/v1/runtime/active-connections 从 backend 会话注册表返回 sshCountsftpCount 及二者之和 totalCount
  • DELETE /api/v1/runtime/active-connections 关闭当前所有已注册 SSH/SFTP 会话,并返回本次关闭的数量。
  • Electron Main 模式下两个 HTTP 操作都要求内部 token。它们不会通过 preload.ts 暴露,因此 renderer 既不能批量断开会话,也不能向守卫提供活动计数。
  • app:close-window 保持现有 fire-and-forget 签名。守卫挂在主 BrowserWindow 的关闭生命周期上,因此标题栏关闭、最后标签页关闭、macOS close role 与应用退出共享同一权威判断。
  • 仅当权威探测要求确认时,Main 才发送 app:close-confirmation-request。Renderer 使用共享 Dialog 展示警告,再返回 app:close-confirmation-response;Main 只接受来自所属 webContents 且不透明 request ID 匹配的响应。

4. 变更规则

当新增/修改 channel 时,必须在一个变更中同步更新:

  1. packages/main/src/preload.ts
  2. packages/main/src/index.ts
  3. packages/renderer/src/vite-env.d.ts
  4. 相关 renderer transport/service 封装
  5. 本文件(docs/zh-CN/developer/core/ipc-protocol.md

5. Channel 新增模板

新增 channel 时建议按以下清单执行:

  1. Channel 命名:domain:action-name
  2. IPC 类型:invokesend
  3. 参数 schema:在 bridge 与 renderer 声明中显式类型化
  4. 返回 schema:成功与错误结构
  5. Main 行为:后端代理或本地特权动作
  6. 安全说明:token/header 处理、权限边界、暴露范围
  7. 文档同步:同一变更集更新中英文协议文档

6. 服务器代理契约

  • ApiSshCreateServerRequest / ApiSshUpdateServerRequest 可携带 proxyMode = default | off | custom 与可选 proxyUrl
  • ApiSshListServersResponse 返回持久化代理模式和 URL,用于编辑与连接规划。
  • ApiSshCreateSessionRequestApiSftpCreateSessionRequestApiPortForwardStartRuleRequest 可携带临时 systemProxyRules;该字段永不持久化。
  • SystemProxyResolveRequestSystemProxyResolveResultpackages/api-contract/src/ipc.ts 中的 IPC-only 类型。
  • Main 根据已校验 host/port 构造解析 URL,Renderer 不能向 Session.resolveProxy 提交任意 URL。