DeepSeek-Reasonix 桌面宿主协议(Desktop Host Protocol)深度解析:Electron 壳层与 Go 服务的 JSON-RPC 2.0 契约
【免费下载链接】DeepSeek-ReasonixDeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running.项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Reasonix
导读
DeepSeek-Reasonix 的桌面应用由 Electron 壳层与 Go 桌面服务两个进程组成,二者通过一条私有、带版本号的 JSON-RPC 2.0 连接(走服务的 stdio)通信。本文以 docs/DESKTOP_HOST_PROTOCOL.md 为主线,逐层拆解这条协议:传输帧格式、握手与错误码、生命周期请求、业务命令注册与分发、事件投递与断线恢复、native host 反向调用、资源源(resource origin)鉴权、渲染器 preload API,以及性能诊断与安全边界。读完你既能掌握该协议的完整调用链,也能直接基于仓库源码定位各环节的具体实现文件与测试,用于二次开发或排查桌面端问题。
React renderer ──typed IPC (preload)──▶ Electron main ──stdio JSON-RPC──▶ Go desktop service ▲ │ └────── host/* reverse requests ────┘三端各有明确职责:Go 侧拥有全部桌面业务命令(App方法),Electron 侧拥有全部原生界面能力(窗口、对话框、托盘、浏览器)。任何一端都不能绕过契约:React UI 永不触碰 Electron 或 Go 的全局对象,Go 业务代码也永不链接任何 shell 工具包。
一、传输层:新行分隔的严格 JSON-RPC 2.0
帧格式与启动方式
协议帧采用换行分隔的 JSON-RPC 2.0(rpcwire严格模式),每行一帧,UTF-8 编码,不支持 batch 数组。Go 服务以reasonix-desktop --host-rpc方式启动:其 stdout 只承载协议帧,stderr 承载日志。壳层在收到desktop/shutdown后关闭 stdin 请求退出。
对应的启动入口在 desktop/host_rpc.go:exitIfHostLaunchMode检测--host-rpc标志后调用runHostRPC,后者构造rpcwire.NewConn(stdin, stdout, ...)并启动服务循环。
资源限制(三方约定)
| 限制项 | 数值 | 说明 |
|---|---|---|
| 入站帧大小上限 | 64 MiB(双方) | MaxInboundBytes/MaxOutboundBytes |
| 服务端并发入站处理器 | 512 | MaxConcurrentHandlers |
| 写停滞看门狗 | 30 s | MaxWriteStall |
这些参数在 desktop/host_rpc.go 中逐一可见。大体积二进制负载从不放进协议帧,而是走下文"资源源"(resource origin)。
并发与顺序保证
壳层的每个请求都在独立 goroutine 上运行(与已退役的进程内 shell 绑定调用行为一致)。只有desktop/event帧保证顺序——服务端由单一队列写入,实现在 desktop/internal/hostrpc/server.go 的Emit方法:seq与帧写入在同一把锁内完成,因此线上顺序即调用顺序。
二、握手:desktop/hello与终止性错误码
新建连接上的第一个请求必须是desktop/hello,其余任何请求都会以-32002 not_ready失败(服务端通过gated包装器统一拦截,见 desktop/internal/hostrpc/server.go)。
请求与响应示例
// shell → service {"method":"desktop/hello","params":{ "protocolVersion": 1, "contractDigest": "sha256:…", // digest embedded in the shell bundle "build": {"version":"v1.30.0","channel":"stable","commit":"abc123"}, "host": {"name":"electron","version":"44.2.0","chrome":"152.0.0","platform":"darwin","arch":"arm64"}, "instance": {"home":"/Users/…/.reasonix","dev":false} }} // service → shell {"result":{ "protocolVersion": 1, "contractDigest": "sha256:…", "service": {"version":"v1.30.0","channel":"stable","commit":"abc123","pid":4242}, "runtimeGeneration": "g-01J…", // new for every service process "resources": {"origin":"http://127.0.0.1:51234","token":"…"}, "window": {"width":1280,"height":820,"minWidth":760,"minHeight":480,"frameless":false,"zoomFactor":1} }}握手请求/响应的 Go 结构体定义在 desktop/internal/hostrpc/hello.go,客户端校验逻辑在 desktop/electron/src/main/handshake.ts:validateHelloResult会逐字段检查protocolVersion、窗口几何必须为正数等,任何偏差都会抛出HandshakeError。
窗口几何的由来
window是 Go 根据已保存状态与平台规则推导出的主窗口初始几何;壳层先以隐藏窗口创建,待domReady后由 Go 通过host/window.*系列反向调用完成定位、最大化与显示。实际值来自 desktop/host_rpc.go 的Hellohook:initialDesktopWindowSize()、最小尺寸常量760×480(见 desktop/host_rpc.go)、平台相关的frameless与初始zoomFactor。
终止性错误码
握手失败是终止性的:壳层展示真实错误并仅提供"打开日志"与"退出"两个动作,绝不回退到浏览器 mock。
| Code | Name | Meaning |
|---|---|---|
-32001 | protocol_mismatch | protocolVersion不一致 |
-32003 | contract_mismatch | 命令/事件摘要不一致(混合安装) |
-32004 | build_mismatch | 壳层与服务版本不同且均非dev |
-32005 | instance_mismatch | 壳层的规范数据主目录与服务端不一致 |
-32002 | not_ready | 在成功 hello 之前的请求 |
服务端按此顺序执行校验(desktop/internal/hostrpc/hello.go):先比协议版本,再比契约摘要,然后(非 dev 构建时)比版本号,最后用instanceidentity.CanonicalHome归一化后比对数据主目录。客户端侧每个错误码对应的展示文案集中在 desktop/electron/src/main/handshake.ts 的FAILURE_TITLES。
runtimeGeneration:进程代数
runtimeGeneration标记本服务进程签发的每一个事件、每一个审批或浏览器授权。服务重启即产生新代;壳层会丢弃所有携带旧代标记的内容。服务端在runHostRPC中生成"g-" + randomHex(8)(desktop/host_rpc.go),并注入每个desktop/event帧。
三、生命周期请求(shell → service)
| Method | Params | Result | Go owner |
|---|---|---|---|
desktop/start | {} | {} | App.startup |
desktop/domReady | {} | {} | App.domReady |
desktop/rendererAttached | {"rendererGeneration":n} | {} | frontend heartbeat/readiness |
desktop/beforeClose | {"reason":"window"\|"quit"\|"tray"\|"updater"} | {"prevent":bool} | App.beforeClose |
desktop/shutdown | {} | {} | App.shutdown |
desktop/hostEvent | {"name":string,"payload":any} | {} | second instance、tray open/quit、菜单动作 |
desktop/browserControl | {"enabled":bool} | {} | 内置浏览器开关,构建会话时读取 |
每个方法都注册为rpcwirehandler 并经过gated就绪门(desktop/internal/hostrpc/server.go),hook 与App的绑定关系见 desktop/host_rpc.go 的hostRPCHooks:
desktop/start→app.startup(ctx)desktop/domReady→app.domReady(ctx)desktop/rendererAttached→app.ReportDesktopWebViewReady()desktop/beforeClose→bridge.beforeClose(返回prevent布尔)desktop/shutdown→app.shutdown(ctx)
生命周期顺序
hello → start → 窗口加载 → domReady → (rendererAttached 在每次渲染器挂载后) → … → beforeClose → (shutdown → stdin 关闭 → exit)关键健壮性设计:服务端在 stdin 关闭时自行退出,无论shutdown是否被调用——即使壳层突然崩溃,也绝不会遗留无头的 Go 进程。desktop/shutdown通过rpcwire.RespondThen先应答再关闭done通道(desktop/internal/hostrpc/server.go),Serve随即可干净返回。
四、业务命令:desktop/invoke与生成式契约
调用格式
{"method":"desktop/invoke","params":{"method":"OpenProjectTab","args":["/path", true]}} {"result": {...}} // the method's JSON result, null for void {"error":{"code":-32000,"message":"<error text>","data":{"method":"OpenProjectTab"}}}method必须命名 GoApp值上被契约注册表接受的导出方法。签名遵循旧 shell 的规则:任意 JSON 可序列化参数,结果形如()、(T)、(error)或(T, error);注册表在构建期拒绝任何不合规方法,因此契约表面永远不会出现壳层无法调用的方法。壳层在转发前还会对照内嵌命令表校验method,未知名称以-32601失败。服务端分发实现在 desktop/internal/hostrpc/server.go,对未知方法、非法参数、panic、业务错误分别映射-32601、-32602、-32600(内部错误)与-32000(业务错误,data.method注明命令名)。
契约生成:单一事实来源
cd desktop && go run . -emit-contract frontend/src/generated这条命令一次性产出:JSON 契约、其摘要、TypeScript 命令表,以及渲染器消费的 DTO 类型声明。实现见 desktop/host_rpc.go 的emitHostContract:扫描App类型与平台声明,构建注册表后调用hostrpc.Build生成契约,写出desktopContract.generated.ts/desktopContract.generated.json,同时写出desktop/host_command_owners.generated.json。桌面 Go 测试会校验签入的输出与实时生成结果一致,漂移即测试失败。
命令所有权(ownership)元数据
每条命令还记录其源模块domain、精确owner(如App.OpenProjectTab)、仓库相对路径sources、scope与cancellation;这些字段全部计入摘要。宿主把desktop/host_command_owners.generated.json内嵌进二进制,并对每个反射到的命令做校验。scope记录 owner 的具名 wireinputs(未命名的历史参数记作argN)与resolver;零输入命令用owner-state,其余用owner-inputs。这些是溯源(provenance)与分发(dispatch)边界——输入校验、tab/session 选择与访问检查仍留在原App方法内。
取消语义
当前 App 命令声明before-dispatch:宿主在解码前与分发前立即检查取消,并在同步写入期间保持方法结果不因取消而丢失;它们不承诺分发后的中断。宿主方法可选择cooperative-context——以 Gocontext.Context作为首个参数,宿主注入请求上下文并将其排除在 JSON 参数与生成的 DTO 之外,方法必须自行配合取消。业务 Stop/Cancel 命令继续沿用既有 owner 与语义(相关测试见 desktop/internal/hostrpc/cancellation_test.go)。
五、事件流(service → shell → renderer)
{"method":"desktop/event","params":{"seq":1093,"generation":"g-01J…","name":"agent:event","args":[{...}]}}args保留旧事件桥的可变参数负载,多数事件只带一个元素。壳层将帧转发到渲染器的reasonix:event通道;preload APIon(name, cb)按name过滤并调用cb(...args)。序列号按代严格递增,渲染器重新挂载后可借此检测间隙并重新快照,而不是信任过期状态。
断线恢复(resync)机制
服务端 supervisor 与 preload 都拒绝重复或乱序帧;preload 还依据当前服务状态拒绝旧代帧,并在 React 订阅之前绑定传输。发生代变更、序列间隙或错过订阅时,壳层抛出本地事件desktop:resync(携带generation、reason、expectedSeq、actualSeq)——这不是 Go 业务事件。随后:
- 运行时状态通过
SyncRuntimeState重新读取; - 已挂载的控制器重新读取
ListTabs,用既有TurnEventsForTab账本与 pending-prompt 呈现修复投影; - 读取被 fence 住,防止与更新的恢复请求及会话/导航变更竞争;
- 不重放任何业务变更;服务重启后,幸存的渲染器无需重载未发送草稿即可重新挂载。
当前恢复保证覆盖:核心运行时状态、会话元数据、持久化 turn 事件与 pending prompts。终端输出只有有界快照、没有原子输出游标,因此受影响的终端会被明确标记为不完整,而不是把有歧义的快照合并进实时输出。扩展输出、文件监听等独立事件流仍需要各自能力专属的重快照契约,不在核心恢复保证内。
六、Native host 反向调用(service → shell)
这些调用替代了 Go 内的直接 shell 工具包调用,每个方法对应 GonativeHost接口的一个方法;Wails 实现在 Electron 壳层落地时退役。服务端通过server.Request(ctx, method, params, result)发起(desktop/internal/hostrpc/server.go),并注册为rpcNativeHost(desktop/host_rpc.go)。
窗口与系统调用
| Method | Params | Result |
|---|---|---|
host/window.show | {"reason":string} | {} |
host/window.hide | {} | {} |
host/app.hide | {} | {}(macOS 应用隐藏) |
host/window.maximiseunmaximiseminimiseunminimisetoggleMaximisecenter | {} | {} |
host/window.isMaximisedisMinimised | {} | {"value":bool} |
host/window.setPosition | {"x":n,"y":n} | {} |
host/window.setTitle | {"title":string} | {} |
host/screen.list | {} | {"screens":[{"x","y","width","height","scale","primary"}]} |
host/dialog.openDirectory | {"title","defaultDirectory"} | {"path":string}(""= 取消) |
host/dialog.openFile | {"title","defaultDirectory","filters":[{"displayName","pattern"}],"multiple":bool} | {"paths":[]} |
host/dialog.saveFile | {"title","defaultDirectory","defaultFilename","filters"} | {"path":string} |
host/dialog.message | {"type":"info"\|"warning"\|"error"\|"question","title","message","buttons":[],"defaultButton","cancelButton"} | {"button":string} |
host/shell.openExternal | {"url":string} | {} |
host/app.quit | {} | {} |
host/app.relaunch | {"args":[],"execPath"?:string} | {} |
host/devtools.toggle | {} | {} |
host/remoteWindow.open | {"hostKey","url","title"} | {"windowId":string} |
host/remoteWindow.navigate | {"hostKey","url","title"} | {} |
host/remoteWindow.focusclose | {"hostKey"} | {} |
host/tray.ensure | {"openTitle","openTooltip","quitTitle","quitTooltip","tooltip"} | {"ready":bool,"reason":string} |
host/tray.destroy | {} | {} |
安全要点:host/shell.openExternal只接受http:、https:、mailto:URL;file:、javascript:、data:等其他 scheme 在 Electron 宿主边界、系统 opener 被调用之前就被拒绝。对话框结果从不暴露文件内容,只返回路径,Go 侧再经由既有的 workspace 与 media 检查授权。
浏览器授权调用
| Method | Params | Result |
|---|---|---|
host/browser.grantrevoke | {"grantId","tabId","sessionId"}/{"grantId"} | {} |
host/browser.tabs.list | {"grantId"} | {"tabs":[{"id","url","title","loading","temporary"}]} |
host/browser.tabs.open | {"grantId","url","temporary"} | tab |
host/browser.tabs.navigate | {"grantId","tabId","url","action"} | tab |
host/browser.tabs.close | {"grantId","tabId"} | {} |
host/browser.snapshot | {"grantId","tabId","selector"} | {"documentToken","url","title","tree","refs"} |
host/browser.act | {"grantId","operationId","tabId","documentToken","action","ref","text","keys","options","files","submit","deltaX","deltaY"} | {"executed","reason","documentToken"} |
host/browser.screenshot | {"grantId","tabId","ref","fullPage","directory"} | {"path","mime","width","height"} |
host/browser.downloads | {"grantId","tabId","waitForMs"} | {"downloads":[{"id","url","path","state","bytes"}]} |
浏览器调用失败码:-32010(引用过期)、-32011(用户接管了该 tab)、-32012(无当前授权);Go 执行器把它们映射到内核哨兵错误并在账本中记录操作结果。授权下的tabId是桌面 tab(即任务),该授权下打开的浏览器 tab 都归属于它。
Host 事件清单
desktop/hostEvent支持的事件名:tray.open、tray.quit、secondInstance(原始 argv 在payload中)、menu.showWindow、remoteWindow.closed({"hostKey"})、browser.takeover({"tabId","epoch","reason"})。
七、资源源(Resource Origin):大负载与鉴权中转
服务端在一个回环端口上监听既有的已授权资源 handler:
/__reasonix_workspace_media/…(工作区媒体)/__reasonix_theme_asset/…(主题资源)- 远程 markdown 图片代理
壳层以特权 schemereasonix://app/提供打包 UI,并且只把上述前缀转发到资源源,在主进程中附加Authorization: Bearer <token>。token 永不抵达渲染器、网站视图、远程窗口或 MCP App 帧;Go 侧保留现有的全部 file-identity 与 TTL 检查。
实现细节:startResourceOrigin随机回环端口 +bearerAuth用常量时间比较校验Authorization头(desktop/host_rpc.go);Electron 侧的 scheme 注册与转发路由在 desktop/electron/src/main/protocol.ts(FORWARDED_PATHS必须与 Go 侧三个中间件路径一致)与registerAppProtocol(仅放行reasonix://app主机、拒绝路径穿越、转发时带上accept/range等头并bypassCustomProtocolHandlers)。
八、渲染器 Preload API
可信 preload 只暴露一个对象window.reasonixDesktop(对应实现位于 desktop/electron/src/preload/index.ts):
interface ReasonixDesktopHost { readonly kind: "electron"; readonly contract: { protocolVersion: number; digest: string; commands: readonly string[] }; readonly platform: { os: "darwin" | "windows" | "linux"; arch: string; versions: Record<string, string> }; invoke(method: string, args: unknown[]): Promise<unknown>; on(name: string, cb: (...args: unknown[]) => void): () => void; native: { openExternal(url: string): Promise<void>; clipboard: { writeText(text: string): Promise<boolean>; readText(): Promise<string> }; window: { setTheme(theme: "system" | "light" | "dark"): void; setBackgroundColour(r: number, g: number, b: number, a: number): void; getBounds(): Promise<{ x: number; y: number; width: number; height: number; maximised: boolean }>; isMaximised(): Promise<boolean>; minimise(): void; toggleMaximise(): void; close(): void; }; getPathForFile(file: File): string; // 原生拖放路径 onServiceState(cb: (state: ServiceState) => void): () => void; browserControl: { // 内置浏览器设置页 get(): Promise<BrowserControlState | null>; setEnabled(enabled: boolean): Promise<BrowserControlState>; setIgnoreCertificateErrors(enabled: boolean): Promise<BrowserControlState>; clearCache(): Promise<void>; // 保留 cookies 与站点数据 clearAllData(): Promise<void>; // cookies、站点数据与缓存 importChromeLogin(): Promise<ChromeImportOutcome>; }; }; browser: { // 用户驱动浏览器面板;Agent 调用走 Go list(): Promise<BrowserTabView[]>; open(url: string, opts?: { temporary?: boolean; taskId?: string }): Promise<BrowserTabView>; close(tabId: string): Promise<void>; activate(tabId: string | null): Promise<void>; navigate(tabId: string, target: { url?: string; action?: "back" | "forward" | "reload" | "stop" }): Promise<void>; setZoom(tabId: string, factor: number): Promise<void>; toggleDevTools(tabId: string): Promise<void>; resume(tabId: string): Promise<void>; // 把被接管的 tab 还给 Agent setLayout(rect: { x: number; y: number; width: number; height: number } | null): void; setOverlay(active: boolean): void; // 应用遮罩隐藏所有网站视图 onTabs(cb: (tabs: BrowserTabView[]) => void): () => void; onDownload(cb: (download: BrowserDownloadView) => void): () => void; }; }关键数据类型
BrowserTabView={ id, taskId, url, title, loading, canGoBack, canGoForward, temporary, mode: "agent" | "human", epoch, zoom, error };BrowserDownloadView={ id, tabId, url, filename, path, state, received, total }。- 网站视图位于
persist:browser(共享登录态)或temp:<id>分区,永不获得应用 preload。 ServiceState={ phase: "starting" | "ready" | "restarting" | "failed" | "exited"; generation: string; error?: string }——业务组件只导入类型化 SDK,从不直接读此对象,只有桥接适配器读取它。BrowserControlState={ controlEnabled, ignoreCertificateErrors, writable, warning: "invalid-config" | "unreadable-config" | "unsupported-version" | null }。ChromeImportOutcome为{ ok: true, profile, cookies, skipped }或{ ok: false, reason },reason取chrome-missing、profile-not-found、cookies-unreadable、safe-storage-denied、safe-storage-unavailable、unsupported-platform之一。
九、性能诊断:受限原生调用
以下可选原生调用仅限受信任的应用主帧使用,旧壳层可以省略它们;不需要任何持久化用户数据格式变更或迁移。相关实现分布在 desktop/electron/src/main 下的processDiagnostics.ts、rendererDiagnostics.ts、profileAnalysisHost.ts、profileAnalysisWorker.ts与performanceHost.ts。
processDiagnostics()返回{scope: "electron", samples, growth}。样本含 age、可空 CPU 区间、进程 PID/类型/创建时间、可空 CPU 百分比、工作集与私有内存(MiB)及截断标志。前台每 30 秒采样一次、其他情况每 60 秒一次;保留最多 12 个快照与 5 分钟,每快照最多 128 个进程。不采集标题、URL 或进程名,只覆盖 Electron 托管进程,Go 进程被排除。captureRendererProfile(requestId?)通过 CDP 以请求的 10 ms 采样间隔记录当前渲染器 5 秒,返回状态、时长与至多 8 条 app 脚本 self-time 摘要。普通文档不启用 JS self-profiling。采集单飞(single-flight)、要求前台窗口、遵守 10 分钟冷却、每个壳层生命周期最多 3 次尝试;不接管既有 debugger/DevTools 会话。失焦、隐藏、导航、渲染器丢失或取消都会中止采集。cancelRendererProfile(requestId)只取消匹配的采集;无范围的取消被忽略,这同时 fence 住跨长挂起/恢复间隙的延迟请求。每条 CDP 命令有 1.5 秒截止,自有 debugger 在所有终止路径上释放。分析在一次性 Worker 中运行:32 MiB 老生代上限、1.5 秒截止、20,000 节点 / 100,000 样本输入上限。原始 profile 永不进入 UI 报告。exportHeapSnapshot()要求用户确认的原生警告与保存对话框;本地保存、不上传、不接受渲染器提供的路径。快照可能包含代码、聊天与机密,且可能暂停渲染器或占用大量磁盘;Electron 无法抢占快照——其 busy lease 会一直持有到实际操作落定。
内存增长信号判定
需要连续 PID + 创建时间身份、跨 2 分钟至少 5 次读数,且最近 3 次读数相比最初 2 次基线同时超出 256 MiB 与 50%。全程优先使用私有内存,否则使用工作集。这是"持续增长"的观测信号,不是泄漏证明,也不代表独占物理 RAM。
报告立即出现;进程富化最多等待 750 ms,有界 CPU 采集稍后可更新同一报告;UI 在 12 秒后放弃采集富化并请求取消。这些是异步截止而非同步工作的抢占限制;已关闭的报告永不重现。报告区分触发后样本与已结束的长任务;用户请求的堆快照在采集期间及随后的 5 秒沉降宽限内抑制压力告警。
自带验证脚本
在desktop/electron下:
node scripts/performance-smoke.mjs # 验证生产 owner、Worker、报告富化与本地堆快照(隔离原生 fixture) node scripts/performance-benchmark.mjs # 关闭 / 轻量监控 / 短采集 三种模式,各 3 个全新进程对比基准脚本把所有模式的渲染器 bundle 与运行时模式选择固定一致,固定 activity 信号并禁用后台节流以保证无人值守测量,在artifacts/performance/overhead.json记录 CPU 时间、帧时序、工作集与采集开销。该合成基准并非 Windows 用户负载的复现,现场对比仍需覆盖启动、长时间使用、前台返回与关闭 tab 等场景。
十、安全边界总览
| 边界 | 规则 |
|---|---|
| 应用窗口 | sandbox 开启、context isolation 开启、Node integration 关闭、仅reasonix://app、preload 如上 |
| 网站视图 / 远程 Serve 窗口 / MCP App 帧 | 独立 session、无应用 preload、无reasonix://访问、无host/*可达 |
| IPC 处理 | 只接受来自应用窗口webContents的请求,其他发送者一律拒绝并记录日志 |
| 业务调用 | 契约之外的desktop/invoke名称在到达 Go 之前即被拒绝 |
配套测试覆盖了握手校验(desktop/electron/src/main/handshake.test.ts)、契约一致性(contract.test.ts)、IPC 白名单(ipc.test.ts)、浏览器控制(browserControlHost.test.ts)、性能诊断(performanceHost.test.ts、rendererDiagnostics.test.ts)以及 Go 侧的注册表/所有权/取消/浏览器控制测试(desktop/internal/hostrpc 目录)。协议级契约常量与错误码在 Go(desktop/internal/hostrpc/hello.go)与 TypeScript(desktop/electron/src/main/handshake.ts)两侧保持一致,任何一侧改动都会触发摘要校验失败,这正是这套"双进程单契约"架构能够长期安全演进的根基。
延伸阅读
- 协议规范中文版:docs/DESKTOP_HOST_PROTOCOL.zh-CN.md
- 桌面宿主架构总览:docs/DESKTOP_SHELL_MIGRATION.md 与 docs/APP_SHELL.md
- Go 服务端入口:desktop/host_rpc.go、desktop/main.go
- 契约注册与生成:desktop/internal/hostrpc/registry.go、desktop/internal/hostrpc/typescript.go、desktop/host_command_owners.generated.json
- Electron 壳层:desktop/electron/src/main/index.ts、desktop/electron/src/main/service.ts、desktop/electron/src/main/rpc.ts
【免费下载链接】DeepSeek-ReasonixDeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running.项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Reasonix
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考