从 Web 到桌面:AI Mind Electron Desktop Host 的安全边界设计

从 Web 到桌面:AI Mind Electron Desktop Host 的安全边界设计

本文基于 AI Mind 项目的真实实现整理。

GitHub:github.com/HWYD/ai-min...

对应代码版本:v0.5.0

线上链接:ai.hwyblog.cloud/instant-min...

AI Mind 是一个持续迭代中的 Next.js AI Chat 项目。从最基础的本地聊天开始,逐步加入流式协议、工具调用、MCP、Skill、Agent、图像生成和桌面端入口。

如果你对这个项目感兴趣,或者这篇文章对你有一点帮助,也欢迎顺手到 GitHub 帮 AI Mind 点个 Star⭐,这会是对我继续更新很大的鼓励。

在前面的版本里,AI Mind 已经逐步完成了聊天、工具调用、MCP、受控 Agent、HITL、checkpoint resume、多会话和图像生成等能力。

这些能力都跑在现有的线上 Web Runtime 里。

到了 v0.5.0,我开始给 AI Mind 增加桌面端入口。

一开始看,这好像只是一个 Electron 套壳问题:

text 复制代码
打开一个 BrowserWindow
加载线上 URL
打包成 exe / dmg

但真正落到一个长期可维护的 AI 应用里,问题会复杂很多:

text 复制代码
桌面端要不要打包 Next.js 服务?
要不要在本地保存数据库?
模型、MCP、Agent Runtime 要不要搬到桌面端?
远程页面能不能拿到 Node.js 或 IPC 能力?
用户能不能修改服务地址?
线上服务升级后,旧桌面端还能不能继续加载?
关闭桌面应用时,正在生成的流式回答要不要 cancel?
网络失败、TLS 失败、本地 profile 损坏时,用户怎么恢复?
未签名公开 Beta 要如何发布和校验?

所以 v0.5.0 的重点不是"把 AI Mind 套进 Electron",而是:

在不复制线上 AI Runtime、不向远程页面开放本机能力、不破坏既有会话和流式恢复语义的前提下,为 AI Mind 增加一个可长期维护的桌面宿主。

这篇文章复盘的就是这个过程。


1. 为什么 AI Mind 要做桌面端

AI Mind 本身已经是一个 Web 应用,用户可以直接在浏览器中使用。

那为什么还要做桌面端?

我的考虑主要有三个。

第一,桌面端更像一个长期产品入口。浏览器标签页适合快速访问,但独立桌面窗口更接近用户对"工具"的使用习惯。

第二,桌面端可以保留现有 Web Runtime。v0.5.0 并不是重写一套桌面 AI Mind,也不是把线上服务整体搬到用户电脑里,而是继续使用普通聊天、图像生成、受控 Agent、会话恢复和流式回答。

第三,桌面端可以逐步承接更多本地体验,比如系统托盘、快捷入口、本地文件交互、桌面通知等。但在第一版里,我更关注桌面宿主的基本边界是否站得住。

所以 v0.5.0 的桌面端分工很明确。

线上 webapp 继续负责:

text 复制代码
聊天
图像生成
受控 Agent
会话
StreamRun
数据库
模型调用
MCP 能力

Electron desktop 只负责:

text 复制代码
独立桌面窗口
固定官方服务地址
Chromium profile
本地失败恢复页
导航、权限和下载边界
脱敏诊断导出
Windows / macOS 打包
公开 Beta 发布链路

也可以这样理解:

桌面端不是第二套 AI Mind。桌面端是现有 AI Mind 的安全宿主。


2. v0.5.0 的定位:Electron Desktop Host,而不是本地 Runtime

v0.5.0 的正式定位是:

text 复制代码
AI Mind Desktop Host

它是一个在线桌面宿主,而不是本地 AI Runtime。

这一版支持:

text 复制代码
Windows x64 Squirrel 安装器
macOS arm64 DMG
面向 GitHub Pre-release 的公开发布 workflow
Unsigned Experimental Preview

这里的 GitHub Pre-release 是发布边界,而不是任意构建完成后就自动创建的下载页。只有固定 Origin 的服务端契约完成生产验证后,才会由同一 source commit 的手动 workflow 创建公开预发布。

这一版不支持:

text 复制代码
macOS Intel x64
universal binary
Developer ID signing
notarization
自动更新
离线模式
本地 AI Runtime

代码结构上,我把 Electron 相关代码收束到独立 workspace:

text 复制代码
apps/
  desktop/
    src/main/             # 主进程、状态机、安全策略、会话和本地协议
    src/preload/          # 仅本地 Chrome/recovery 的窄 bridge
    src/chrome-renderer/  # 本地 Desktop Chrome
    src/recovery-renderer/# 本地失败/升级/重置/诊断 UI
    tests/{unit,integration,packaged}/
    forge.config.ts
    package.json
  webapp/
    app/api/desktop/compatibility/route.ts
    lib/desktop/compatibility-policy.ts
    lib/security/browser-security-headers.ts
    proxy.ts

apps/desktop 负责 Electron 主进程、本地桌面外壳、本地恢复页、打包配置和桌面测试。apps/webapp 只新增无身份 compatibility API 与 document 请求的浏览器安全响应头,不反向依赖 apps/desktop,也不改变原来的 AI Runtime 分层。

如果 Electron 代码散落在 webapp 里,Web 代码会开始感知桌面端实现细节,Desktop 主进程也容易复用 Web Runtime 内部状态。因此本版的工程拆分原则是:

Electron 特有能力收束到 apps/desktop,webapp 只暴露必要的 HTTP 契约。


3. 为什么首版不做本地 Runtime

做 Electron AI 应用时,很容易想到把 Next.js 服务、数据库、模型、MCP 和 Agent Runtime 一起搬进安装包。但这会同时引入本地服务生命周期、数据库迁移、模型密钥管理、MCP 安装升级、线上线下会话同步,以及 StreamRun/cancel/resume 跨端一致性等问题。

这些不是不能做,但它们应该成为后续独立版本的主题,而不是第一版桌面宿主一起做。

v0.5.0 选择的路径是:

text 复制代码
AI Runtime 仍然在线上。
Electron 只负责安全承载线上服务。

这样可以复用现有聊天和 Agent 能力、会话和流式恢复语义、部署和数据库,同时避免本地数据迁移和桌面端/Web 端出现两套业务规则。

首版桌面端先解决入口、安全、会话、恢复和发布链路问题,不急着复制一套本地 Runtime。


4. 固定 Origin 与 compatibility gate:启动前先确认能不能加载

公开 Beta 使用固定官方生产 HTTPS Origin,用户不能在 UI、配置文件或环境变量里随意修改。开发模式才接受显式的 localhost 或 127.0.0.1 HTTP Origin,且两者在 build-config.ts(构建期桌面配置)中严格分开:

ts 复制代码
export function createDesktopBuildConfig(input: {
    desktopVersion: string
    developmentOrigin?: string
    isPackaged: boolean
}): DesktopBuildConfig {
    if (input.isPackaged) {
        return createConfig(input.desktopVersion, 'production', PRODUCTION_TRUSTED_ORIGIN)
    }
    if (!input.developmentOrigin) {
        throw new Error('A development origin must be explicitly provided.')
    }
    return createConfig(input.desktopVersion, 'development', parseDevelopmentOrigin(input.developmentOrigin))
}

桌面端启动时不是直接加载 /instant-mind,而是先检查一个无身份、版本化的 compatibility API。启动、重试或 reset 都会创建一个新的 attemptId,兼容性请求、DTO 解析和首次工作区加载共用五秒预算:

text 复制代码
process start / retry
  -> acquire single-instance lock
  -> initialize persistent profile + security handlers
  -> create attempt { id, deadlineAt = now + 5s }
  -> compatibility check
     -> compatible              -> remote work window
     -> manual_upgrade_required -> packaged local recovery window
     -> unavailable/invalid/TLS -> packaged local recovery window

只有 compatible 结果可以创建并加载远程工作视图。网络、TLS、HTTP、schema、contract version、超时或首屏加载失败,都会进入本地 recovery;过期 attempt 的异步回调不能把 recovery 切回工作区。

服务端 route 的边界很窄:它严格检查 Accept 和桌面版本 header,只调用无状态的版本 policy,返回 strict JSON、Cache-Control: no-store 和 X-Content-Type-Options: nosniff,不读取 cookie、不访问数据库、不创建会话,也不返回升级 URL 或 capability 列表。

ts 复制代码
const desktopCompatibilityAccept = 'application/vnd.ai-mind.desktop-compatibility+json; version=1'

export function GET(request: NextRequest) {
    if (request.headers.get('accept') !== desktopCompatibilityAccept) {
        return Response.json(
            { code: 'DESKTOP_COMPATIBILITY_ACCEPT_INVALID', error: 'Desktop compatibility contract is not accepted.' },
            { headers: responseHeaders, status: 406 }
        )
    }

    const result = resolveDesktopCompatibility(request.headers.get('x-ai-mind-desktop-version'))
    if ('kind' in result) {
        return Response.json(
            { code: 'DESKTOP_COMPATIBILITY_VERSION_INVALID', error: 'Desktop version is invalid.' },
            { headers: responseHeaders, status: 400 }
        )
    }
    return Response.json(result, { headers: responseHeaders })
}

桌面端 compatibility.ts(兼容性客户端)使用 workspace session 的 Chromium 网络栈,凭据显式省略,并使用当前 attempt 的剩余时间:

ts 复制代码
response = await input.session.fetch(new URL(input.config.compatibilityPath, input.config.trustedOrigin).toString(), {
    credentials: 'omit',
    headers: {
        accept: 'application/vnd.ai-mind.desktop-compatibility+json; version=1',
        'x-ai-mind-desktop-version': input.config.desktopVersion,
    },
    method: 'GET',
    signal: AbortSignal.timeout(remainingDeadlineMs),
})

桌面端不要直接加载远程页面。先做版本兼容性检查,再决定是否进入工作窗口。


5. 远程工作窗口的安全边界:零本机能力

Electron 最大的风险之一,是远程页面拿到本机能力。

如果一个远程页面既能运行 Web 代码,又能通过 preload、IPC 或 Node.js 访问本机能力,那么它的安全边界就不再是普通网页,而更接近本机应用。

v0.5.0 的远程工作窗口选择了最保守的策略:

text 复制代码
nodeIntegration = false
contextIsolation = true
sandbox = true
no preload
no generic IPC
不暴露 shell.openExternal
不暴露文件系统
不暴露系统权限 bridge

即使远程页面来自官方 AI Mind 服务,也不能默认获得本机能力。自己的站点也可能有 XSS、依赖注入、错误配置、内容策略漏洞;一旦 Web 层出问题,影响范围不应被放大到用户本机。

实际工作区位于本地 Desktop Chrome 下方的 WebContentsView,关键配置如下:

ts 复制代码
contentPreferences: {
    allowRunningInsecureContent: false,
    contextIsolation: true,
    experimentalFeatures: false,
    nodeIntegration: false,
    sandbox: true,
    session: input.session,
    webSecurity: true,
    webviewTag: false,
}

这里没有 preload。远程工作页只作为 Web 页面运行,不能通过 Electron 获得额外本机权限。

security-policy.ts(工作区安全策略)再把导航、弹窗、权限和下载收束到主进程:

ts 复制代码
input.webContents.on('will-navigate', preventUntrustedNavigation)
input.webContents.on('will-frame-navigate', event => preventUntrustedNavigation(event, event.url))
input.webContents.on('will-redirect', preventUntrustedNavigation)
input.webContents.setWindowOpenHandler(() => ({ action: 'deny' }))

input.session.setPermissionCheckHandler((_webContents, permission, requestingOrigin, details) =>
    shouldAllowWorkspacePermission({
        isMainFrame: details.isMainFrame,
        permission,
        requestingOrigin,
        trustedOrigin: input.trustedOrigin,
    })
)

TLS 校验继续由 Chromium 的正常信任链处理,桌面端没有证书绕过或 HTTP fallback。

Electron 安全不是只防第三方网站,也要防自己的远程页面越权。


6. 本地 recovery 页怎么实现:独立 session + 窄 IPC

如果 compatibility check 失败,或者网络、TLS、本地 profile 出问题,桌面端不能继续加载工作窗口,但也不能直接崩溃。

所以 v0.5.0 设计了本地 recovery 页面。它不是线上页面,也不是普通错误页,而是随安装包一起分发的本地页面。

它的职责很窄:

text 复制代码
重试固定官方 Origin
显示手动升级说明
执行用户确认后的本地资料重置
复制或导出脱敏诊断信息

它不能加载任意外部 URL,不能打开外部升级链接,不能读取线上 cookie、工作页 cache 或 Service Worker,也不能调用通用本机 API。

远程工作窗口使用持久 profile:

text 复制代码
persist:ai-mind-desktop

本地 recovery 页使用非持久 session:

text 复制代码
ai-mind-desktop-recovery

它们由 session-profile.ts(会话 profile 与本地重置)统一创建:

ts 复制代码
export function createDesktopSessions<Session>(fromPartition: (partition: string) => Session) {
    return {
        workspaceSession: fromPartition('persist:ai-mind-desktop'),
        recoverySession: fromPartition('ai-mind-desktop-recovery'),
    }
}

recovery 通过包内 protocol 加载,例如 ai-mind-desktop://local/...。local-protocol.ts(本地资源协议)只允许访问资源清单中的 Chrome 和 recovery HTML、JavaScript、CSS,并为每个响应设置独立 CSP;query、hash、路径遍历、未知 host/path 和白名单外资源都会被拒绝。

recovery 的 preload 只暴露四个具名操作:

ts 复制代码
const recoveryApi: RecoveryBridgeApi = {
    confirmResetProfile: input => ipcRenderer.invoke(recoveryBridgeChannels.confirmResetProfile, input),
    copyDiagnostic: () => ipcRenderer.invoke(recoveryBridgeChannels.copyDiagnostic),
    exportDiagnostic: () => ipcRenderer.invoke(recoveryBridgeChannels.exportDiagnostic),
    retry: () => ipcRenderer.invoke(recoveryBridgeChannels.retry),
}

contextBridge.exposeInMainWorld('aiMindRecovery', recoveryApi)

主进程还会验证 sender、当前 recovery URL、参数 schema 和并发状态,因此这不是一条可被远程页面复用的通用 IPC。

recovery 页不是普通错误页,而是一个本地安全边界。它必须和远程工作页隔离。


7. 桌面本地状态和线上业务状态怎么分开

v0.5.0 不新增业务数据库表,这一版做的是状态边界划分。

状态 事实源 负责什么 不负责什么
DesktopBuildConfig 包内常量 桌面版本、固定 Origin、产品 identity、分发标识 用户配置、secret、任意 server URL
DesktopPreviewManifest 打包后生成的只读文件 版本、平台、Electron 版本、SHA-256、public-beta/unsigned 下载 URL、签名凭据、用户资料
DesktopSessionProfile Chromium persistent session cookie、IndexedDB、localStorage、cache 服务端密钥、数据库凭据、业务状态
DesktopCompatibilityState 启动期检查结果 compatible / upgrade / unavailable 聊天内容、cookie、原始异常
DesktopRecoverySession Electron memory session recovery 页本地状态 线上 cookie、cache、Service Worker、工作页权限
DesktopHostState Electron main process 启动、窗口类型、attempt、compat state StreamRun、Agent state、用户业务数据
Existing webapp / StreamRun 线上 AI Mind 服务 chat、Agent、image、idempotency、cursor、cancel Electron 本地实现细节

这个分层的目的,是避免桌面端接管业务事实源:

text 复制代码
桌面端保存 cookie,但不决定用户是否有权限。
桌面端保存 profile,但不保存聊天业务状态。
桌面端知道 compatibility state,但不保存 GraphState。
桌面端可以 reset 本地资料,但不删除服务端数据。

桌面端保存的是浏览器资料,不保存 AI Mind 的业务状态。

这和前面几个版本的设计是一致的。v0.3.x 里,业务状态和 checkpoint 分开;v0.4.x 里,聊天线程状态仍然由服务端 Runtime 管理;v0.5.0 里,Electron 也不能越界成为新的业务状态源。


8. 会话、流式恢复和关闭行为

桌面端接入后,一个很实际的问题是:会话怎么保留?

v0.5.0 没有重新设计一套本地身份系统。桌面端和网页端都使用服务端签发的持久会话 cookie,每次正常使用会将有效期续至未来 30 天,连续 30 天未使用才失效。

Electron 负责保存 Chromium profile,服务端负责 cookie 的授权、续期和失效。也就是说:

text 复制代码
Electron 主进程不读取 cookie。
Electron 主进程不构造 cookie。
Electron 主进程不续期 cookie。
Electron 主进程不判断用户身份。

reset 也不会删除服务端数据。它只清理固定 Origin 对应的本地 trusted profile:

ts 复制代码
export function clearWorkspaceProfile(session: SessionWithClearData, trustedOrigin: string): Promise<void> {
    return session.clearData({
        dataTypes: ['cache', 'cookies', 'downloads', 'fileSystems', 'indexedDB', 'localStorage', 'serviceWorkers', 'webSQL'],
        origins: [trustedOrigin],
    })
}

整体流程是:

text 复制代码
用户点击 reset
  -> recovery 页请求确认
  -> 主进程销毁远程工作窗口
  -> 清理 trusted Origin 对应的本地浏览器数据
  -> 重新进入 compatibility check

流式回答还在生成时关闭桌面应用怎么办?v0.5.0 不伪造 cancel。关闭、崩溃、休眠和重开都不主动创建取消请求;重开后也不会重新挂接仍在活动中的流式订阅,更不会伪造成"已完成"。

它只按现有 Web 端的 hydration 和已持久化终态读取规则展示结果。如果桌面窗口关闭就主动 cancel,桌面端就改变了服务端 StreamRun 语义;如果重开后伪造完成结果,前端就可能展示一个并不存在的终态。

桌面端不要因为窗口关闭,就擅自改写服务端流式状态。


9. 权限、导航、下载:桌面端要默认拒绝

Electron 桌面端一旦提供本机窗口,读者很容易误以为它应该像普通桌面应用一样开放更多能力。

但 v0.5.0 的策略是反过来的:

默认拒绝,只为明确场景开窄口。

默认拒绝包括:

text 复制代码
off-origin navigation
redirect / frame / popup
file: / javascript: / data: / 非本地 protocol
未声明 permission
clipboard read
file system access
device access
自动下载
外部打开请求

这里有一个实现细节:外部链接打开。

一开始可能会认为,用户主动点击的安全 https:// 链接可以交给系统浏览器打开。但在实际验证里,Windows / Electron 行为没有提供足够稳定的 metadata 来区分真实用户点击和脚本触发。因此 v0.5.0 最终选择:外部打开 allowlist 为空,所有外部打开请求都拒绝,不调用 shell.openExternal。

text 复制代码
不能稳定识别安全条件时,不做"看起来方便"的放行。

下载策略也同样收敛。v0.5.0 只允许用户主动触发的受信图片保存:

text 复制代码
必须来自受信工作区主框架
必须有用户手势
必须是同源 blob: 的单一 URL chain
必须经过原生保存对话框
不允许自动下载
不允许 redirect chain 绕过判断
不把保存路径写进诊断

security-policy.ts 对允许的图像下载只设置保存对话框选项,而不把路径交给 renderer:

ts 复制代码
if (!decision.allowed) {
    event.preventDefault()
    return
}

item.setSaveDialogOptions({
    defaultPath: decision.filename,
    filters: [{ extensions: [decision.extension], name: '图像文件' }],
})

不要把 Web 页面升级成拥有本机权限的页面。桌面能力必须白名单化。


10. 发布链路:server-first public beta

Electron 项目很容易把发布理解成:

text 复制代码
打包 exe / dmg
上传 GitHub Release
用户下载

但 v0.5.0 的发布链路不是这样。

因为这个桌面端依赖固定官方线上服务。它能不能工作,不只取决于安装包,也取决于线上 compatibility API 和页面安全响应头是否已经部署。

所以发布顺序必须是 server-first。

大致流程是:

text 复制代码
1. 部署同一 source commit 的 webapp compatibility API 和安全 header
2. 运行 production verification
3. fixed Origin 验证通过
4. 手动触发 public release workflow
5. 构建 Windows x64 / macOS arm64 未签名制品
6. 生成 desktop-release.json 和 SHA-256
7. 验证实际 package fuse / hash
8. 完成 fresh install / overlay install smoke
9. 创建 GitHub Pre-release

在 server compatibility 没有验证通过之前,不应该创建公开 Pre-release,也不应该分发安装器。否则安装包和线上服务可能处于不兼容状态。

公开发布 workflow 的入口把这条约束写成了显式参数:

yaml 复制代码
on:
  workflow_dispatch:
    inputs:
      source_commit:
        required: true
      production_verified:
        description: Confirm that production deployment and verify-production.sh passed
        required: true
        options: ['false', 'true']

jobs:
  windows:
    if: inputs.production_verified == 'true'

Windows 和 macOS job 会针对对应平台生成 installer 或 DMG、平台化 desktop-release.json 和 SHA-256,并在发布前校验真实 executable 的 fuses 与打包内容。

Electron 发布不是只产出安装包,还要和服务端兼容契约一起发布。


11. 实现过程中最值得写的几个踩坑点

v0.5.0 的实现里,有几个点比较适合单独记录。它们不是这篇文章的主线,但能让读者看到真实工程复杂度。

11.1 CSP 和桌面本地 UI 样式

桌面端接入后,Web 页面和 Electron 本地页面都需要安全响应头或本地 CSP。

Web document 为了兼容 Next.js、Radix UI 以及运行时样式,最终需要允许:

text 复制代码
style-src 'self' 'unsafe-inline'

但这个例外不能扩散到 script-src、API response、static resource、prefetch 或 Electron local CSP 的其他资源边界。

本地 Chrome / recovery 页面也类似:可以允许受控的本地样式例外,但脚本仍然必须保持:

text 复制代码
script-src 'self'
禁止 unsafe-eval
禁止白名单外资源

Web document 的脚本仍由 request nonce 和 strict-dynamic 约束;样式兼容例外只解决样式问题,不能顺手放宽脚本策略。

11.2 本地 Desktop Chrome 顶栏

v0.5.0 不只是加载一个网页。为了让桌面端更像真实应用,它还增加了本地 Desktop Chrome:

text 复制代码
AI Mind 标识
查看菜单
帮助菜单
Windows 原生 titleBarOverlay controls
macOS traffic lights
拖动区域
no-drag 交互区
固定 /instant-mind workspace

Windows 和 macOS 的窗口控制区域不同,拖动区域也不同。菜单点击区域必须是 no-drag,否则用户点不到菜单;空白区域又应该保留拖动能力,否则窗口移动体验会很差。

实现上,Windows 的顶栏高度为 40px,titleBarOverlay 保留右侧系统控制;macOS 使用 hiddenInset 保留左侧 traffic lights。Desktop Chrome 的本地 bridge 只接受 view、help 两个菜单名,并校验 sender URL 与菜单坐标,远程工作页并不拥有这条 bridge。

11.3 CI、打包和安装验证不是一次成功

Electron 进入双平台打包后,验证成本会明显上升。

v0.5.0 需要覆盖:

text 复制代码
workspace lint
typecheck
stable tests
build
desktop unit tests
desktop integration tests
package audit
fuse/hash verification
Windows lane
macOS arm64 lane
fresh install smoke
overlay install smoke
server-first production verification

这里的重点不只是生成 Squirrel 和 DMG。发布脚本还会生成和检查 release manifest、SHA-256、真实 executable 的 fuse 状态以及 package 内容;公开发布前,服务端验证和双平台安装 smoke 仍然属于同一条验收链路。

Electron 工程难点不只在写窗口,而在安全策略、跨平台 UI、CI、打包、发布和验收证据。


12. 这一版刻意不做什么

v0.5.0 的范围必须明确。

这一版不做:

text 复制代码
本地 AI Runtime
离线模式
自动更新
Developer ID signing
notarization
Intel Mac
universal binary
任意 Origin
应用内升级 URL
远程页面本机 API
完整本地身份系统
新的服务端部署路径

这些不是永远不做,而是不适合放进 v0.5.0。尤其是本地 Runtime、自动更新、签名/公证和离线模式,每一项都足够成为一个独立版本。

v0.5.0 更像是桌面化的第一块地基:

text 复制代码
固定服务地址
启动兼容性检查
远程窗口零本机能力
本地 recovery
会话资料复用
server-first 发布
公开 Beta 制品验证

地基先稳定,后面再考虑更复杂的桌面能力。


13. 总结:Electron 桌面端不是简单套壳,而是宿主边界设计

做完 v0.5.0 后,我对 Electron 接入 AI 应用有一个更明确的感受:

桌面端不是把网页装进一个窗口这么简单。

尤其是 AI 应用已经有会话、流式恢复、Agent、图像生成、模型调用和服务器状态时,桌面端首先要回答的不是"怎么打包",而是:

text 复制代码
可信服务地址如何固定?
远程页面能不能拿本机能力?
加载前如何确认版本兼容?
失败时如何安全恢复?
会话资料保存在哪里?
服务端流式状态是否被桌面端改写?
本地 reset 会不会删除服务端数据?
发布时如何保证 server 与 desktop 同步?
未签名公开 Beta 如何标识和校验?

v0.5.0 的答案是:

text 复制代码
只做 Online Host。
不复制线上 AI Runtime。
固定官方 HTTPS Origin。
远程工作窗口零本机能力。
兼容才加载,失败进 recovery。
桌面只保存 Chromium profile。
会话和业务状态仍由服务端负责。
发布先验证 server,再发布 desktop。
公开 Beta 明确标记 unsigned experimental preview。

这也是这篇文章想表达的核心:

v0.5.0 的重点不是"把 AI Mind 套进 Electron",而是在不复制线上 AI Runtime、不向远程页面开放本机能力、不破坏既有会话和流式恢复语义的前提下,为 AI Mind 增加一个可长期维护的桌面宿主。

从工程角度看,这个版本不是最显眼的功能版本。它没有新增一个模型能力,也没有新增一个 Agent 类型。

但它让 AI Mind 从 Web 项目往桌面产品形态迈了一步,而且这一步没有牺牲原有 Runtime 的边界。

这对后续继续做桌面增强、本地能力和多端体验,是一个比较稳的起点。


项目地址

GitHub:github.com/HWYD/ai-min...

线上体验:ai.hwyblog.cloud/instant-min...

如果这篇文章或者 AI Mind 项目对你有所帮助,也欢迎顺手帮项目点个 Star⭐。这个支持对我来说很重要,也会让我更有动力继续整理后续版本的实现过程、设计取舍和踩坑复盘。

相关推荐
Csvn1 小时前
📡 前端错误监控从零搭建:window.onerror 与 unhandledrejection 的完整实践
前端
jarvisuni1 小时前
翻车了!GPT5.6接手Opus4.8的项目之后!
前端·人工智能·ai编程
雨田言炎2 小时前
十、QThread多线程
linux·服务器·开发语言·前端·qt
IT_陈寒2 小时前
Vite热更新失效?我的几个犯傻操作害我debug两小时
前端·人工智能·后端
晓得迷路了2 小时前
栗子前端技术周刊第 141 期 - Next.js 16.3、npm 安全事件、2026 CSS 现状调查报告结果...
前端·javascript·npm
2601_965798472 小时前
Launch Your Wellness App Fast: The Truth About Meditation Source Code
前端·macos·ios·objective-c·cocoa
周小董2 小时前
[1367]npm 安装 canvas 报错 node-gyp ERR
前端·npm·node.js
智脑API2 小时前
Codex config.toml check_for_update_on_startup 怎么关闭?离线环境与版本提醒排查
运维·服务器·前端
存在的五月雨3 小时前
前端布局-flex
前端