> For the complete documentation index, see [llms.txt](https://tinyhumans.gitbook.io/openhuman/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tinyhumans.gitbook.io/openhuman/zh/kai-fa/architecture/tauri-shell.md).

# Tauri 外壳

\`crates/openhuman-app/\` 中的桌面宿主：Tauri v2 webview、IPC 命令、嵌入式核心的生命周期以及 JSON-RPC 桥接。

`crates/openhuman-app/` 是 OpenHuman 的桌面宿主。它提供 Tauri v2 webview、IPC 命令和窗口管理，并桥接到嵌入式 `openhuman-core` 核心 JSON-RPC 之上的 Rust 运行时。它不会重复领域栈。那部分位于 `crates/openhuman-core` （库 `openhuman_core`； `openhuman-core` 二进制是 `crates/openhuman-cli/src/main.rs`).

### Shell 所在的位置

Shell 是严格 crate 链之上的三个宿主之一，并且 `openhuman-rpc` 是其中唯一的 OpenHuman crate `Cargo.toml`:

```
  openhuman-app（此 crate）
        |  [dependencies] openhuman-rpc  （http-client、server、jev + 产品 gate）
        v
  openhuman-rpc ----------> host::desktop / host::cli、server、client
        |                    重新导出 `embed` 和 `tinyhumans`
        v
  openhuman-tinyhumans ---> SDK 传输，session 所有者（`session/` 使用它）
        |
        v
  openhuman-embed --------> 运行时、进程辅助工具（tokio 运行时、日志、
        |                    Sentry 选项）、config/artifacts/modules 外观
        v
  openhuman-core
```

| Shell 代码                                                   | 经过                                                                                                               |
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| 嵌入式服务器（`core_process.rs`)                                  | `openhuman_rpc::host::desktop(DesktopOptions { port, rpc_token, .. }, shutdown, ready_tx)`                       |
| `OpenHuman 核心 …` / `mcp` 子命令（`lib.rs::run_core_from_args`) | `openhuman_rpc::host::cli(args)`                                                                                 |
| Tauri 异步运行时大小（`lib.rs::run`)                               | `openhuman_rpc::embed::process::tokio_runtime()`                                                                 |
| Sentry 客户端（`lib.rs::run`)                                  | `openhuman_rpc::embed::process::sentry::client_options` （共享的 `before_send` 链；后备用户 ID 来自 `session::peek_user_id`) |
| 文件日志（`file_logging.rs`），数据重置日志句柄                           | `openhuman_rpc::embed::process::{init_for_embedded, log_directory, shutdown_file_guard}`                         |
| 配置 / 工作区路径、制品、捆绑模块                                         | `openhuman_rpc::embed::{config, artifacts, modules}`                                                             |
| Session 所有者（`session/`)                                    | `openhuman_rpc::tinyhumans`                                                                                      |
| 编译期断言                                                      | `openhuman_rpc::embed::{VOICE_COMPILED_IN, HTTP_SERVER_COMPILED_IN}`                                             |

`scripts/ci/check-crate-chain.mjs` 如果 Shell 的清单命名了另一个 OpenHuman crate 或其 `src/` 名称，则失败 `__host`, `core_host` 或 `openhuman_core::`。每个进程只有一个 embed 运行时：当 Shell 重启其嵌入式服务器时， `CoreProcessHandle` 会等待旧任务（以及其拥有的运行时）退出后，才会启动下一个。

## 职责

1. Web UI。从以下位置加载 Vite 构建： `app/dist` （或 1420 端口上的开发服务器）。
2. IPC。暴露一组明确的 Tauri 命令（见 [Tauri IPC 命令](#tauri-ipc-commands-cratesopenhuman-app)).
3. 核心生命周期。将核心 JSON-RPC 服务器作为进程内 tokio 任务运行（`core_process.rs`）并通过以下方式将其 URL/bearer 交给渲染器： `core_rpc_url` / `core_rpc_token`.
4. 窗口和托盘。桌面窗口行为（主窗口和 mascot 窗口）以及系统托盘（见 `lib.rs`).
5. Session 所有权。让用户登录并保持当前用户为最新（`session/`，由 `openhuman_tinyhumans::session`）：交换登录令牌，针对以下内容验证 JWT： `GET /auth/me`，缓存 `/auth/me`，并通过以下方式将生成的凭据交给核心： `auth.set_credential`。核心本身绝不会直接与后端的认证端点通信。

## 核心进程模型

桌面应用以内嵌方式链接核心，因此本地构建不需要预置的 `openhuman-core-*` sidecar。  `core:stage` 脚本在 `app/package.json` 是为了保持脚本兼容性而保留的空操作。

## 卡住进程恢复

正常退出应用会执行来自 `RunEvent::ExitRequested`：长期运行的扫描任务停止，嵌入式核心的取消令牌触发。最后的进程清理随后发送 `SIGTERM` 给直接子进程，并在短暂宽限期后， `SIGKILL` 给任何仍未退出的进程。清理摘要会记录为 `[app] sweep: term=N kill=M total=K`；任何非零 `kill` 计数都是警告，表示某个子进程忽略了优雅关闭。

在 macOS 上，强制退出（Force Quit， `SIGKILL`、渲染器崩溃）可能会跳过正常清理。下一次启动会在应用运行时启动前运行启动恢复： `.app/Contents`，跳过当前进程，发送 `SIGTERM`， `SIGKILL`清理仍然匹配相同 pid+command 的残留进程。日志使用 `[startup-recovery]` 前缀。

当……时会跳过启动恢复 `OPENHUMAN_CORE_REUSE_EXISTING=1` 被设置时，手动复用 CLI-core 仍然可用。Tauri 命令 `process_diagnostics_list_owned` 返回当前拥有的进程列表；macOS 实现以 bundle 为范围，Linux 和 Windows 返回空列表。

## Tauri Shell 架构（`crates/openhuman-app/`)

### 概览

该 `crates/openhuman-app` crate（Cargo 包 `openhuman-app`，lib `openhuman`，binary `OpenHuman`）是仅限桌面的宿主。它嵌入 React UI，注册插件（深度链接、opener、OS、通知、自动启动、更新器），管理主窗口和托盘，并以内嵌方式运行核心 JSON-RPC 服务器。

非桌面目标会在编译时失败（`compile_error!` 在 `lib.rs`).

### 目录结构

`crates/openhuman-app/src/` 是一组扁平的模块，没有 `commands/` 或 `utils/` 子树。关键模块：

```
crates/openhuman-app/src/
├── lib.rs                  # `run()`、托盘/菜单、插件、`generate_handler!`、大多数窗口/更新/生命周期命令
├── main.rs                 # 二进制入口
├── core_process.rs         # CoreProcessHandle：嵌入式核心服务器任务、RPC 令牌、端口冲突处理
├── core_rpc.rs             # 认证辅助工具 + `relay_http_rpc` 宿主侧 HTTP 中继
├── gateway/                # 前端的 RPC 去向：本进程中的核心，或一个
│                           # 位于 URL 的核心，或此应用在容器中提供的一个
│                           # 通过 SSH / 两者（tinybox）。types · store · ops · registry ·
│                           # 命令
├── imessage_scanner/       # 仅限 macOS：直接读取 ~/Library/Messages/chat.db
├── mascot_native_window.rs / window_state.rs
├── native_notifications/
├── artifact_commands.rs    # 制品导出（复制到 Downloads）
├── directory_picker.rs     # 用于文件夹记忆源的原生文件夹选择器
├── external_navigation.rs  # 防止主 webview 导航到应用外；将远程链接交给 OS 浏览器
├── workspace_paths.rs      # 安全的相对工作区文件打开/显示/预览
├── app_update.rs           # 更新器支持（命令位于 lib.rs）
├── loopback_oauth.rs       # 本地主机 OAuth 重定向监听器
├── session/                # Session 所有者：通过 openhuman_tinyhumans::session 提供 auth_* 命令
├── claude_code.rs          # Claude Code 登录启动
├── mcp_commands.rs         # MCP 客户端辅助工具
├── file_logging.rs         # 日志文件接收器 + logs-folder 命令
├── process_recovery.rs / process_kill.rs / local_data_reset.rs  # process_recovery 在 process_recovery/ 下有按平台划分的子模块
├── deep_link_ipc.rs / deep_link_ipc_windows.rs / deep_link_registration_check.rs
└── stderr_panic_hook.rs / reset_reboot_schedule.rs
```

没有 `src-tauri/src/services/session_service.rs` 在这个树中。Session 处理位于 `session/` （见 [Session](#session-session)）、web 层、后端和核心。

### 数据流：UI → core

```
React（fetch）
    → POST http://127.0.0.1:<port>/rpc   （URL 来自 `core_rpc_url`，
                                          bearer 来自 `core_rpc_token`）
        → 嵌入式 openhuman 核心服务器（本进程中的 tokio 任务）
```

渲染器通过 HTTP 直接与本地核心通信： `app/src/services/coreRpcClient.ts` 调用 `core_rpc_url` / `core_rpc_token` 一次，然后发出普通的 `fetch()` 调用。 `relay_http_rpc` Tauri 命令是宿主侧的后备方案，仅在 RPC URL 不是安全 `tauri://localhost` webview 的可信来源时才使用（例如在 LAN IP 上自托管的运行时，会被当作混合内容阻止）。在这种情况下，Rust 宿主会委托给 `openhuman_rpc::post_json_rpc` 来自共享的 `crates/openhuman-rpc` crate（特性 `http-client`）：30 秒超时；当存在 bearer 时禁用重定向；状态和正文原样镜像返回为 `HttpRpcResponse`。Shell 只添加了 gateway 传输守卫（`validate_remote_transport`，特性 `gateways`）后才委托。

`CoreProcessHandle` 在 `core_process.rs` 拥有嵌入式服务器任务（通过以下方式启动 `openhuman_rpc::host::desktop` ，并使用每次启动随机生成的 bearer token）并处理旧监听器/端口冲突恢复。

### 窗口和托盘行为

* Shell 在启动时创建托盘图标（`RunEvent::Ready`）并将动作绑定为打开主窗口或退出。在 Linux 打包运行时会跳过托盘设置（GTK panic）。
* 隐藏到托盘是在 `RunEvent::WindowEvent { CloseRequested }` 处理器中实现的，位于 `lib.rs`，而不是作为 IPC 命令：macOS 会隐藏整个应用（`AppHandle::hide()`），Windows 会隐藏顶层 `Chrome_WidgetWin_1` 窗口，通过 `EnumWindows` 和 `SW_HIDE`.
* 在 macOS 上 `RunEvent::Reopen` （点击 Dock）会恢复并聚焦主窗口。

### 捆绑资源

`tauri.conf.json` 打包 `../../crates/openhuman-core/src/agent/prompts` ，因此核心提示 markdown 会随应用一起发布。

### 相关

* IPC 接口：见 [Tauri IPC 命令](#tauri-ipc-commands-cratesopenhuman-app) 下文
* HTTP 桥接：见 [核心桥接与辅助工具](#core-bridge-and-helpers-cratesopenhuman-app) 下文
* Rust 领域与运行时： `crates/openhuman-core/src/`, `crates/openhuman-core/src/core/`
* 共享 RPC 合约 + HTTP 客户端： `crates/openhuman-rpc/` （也用于 `crates/openhuman-tui` 用于信封解码）

## Tauri IPC 命令（`crates/openhuman-app`)

所有命令都注册在 `crates/openhuman-app/src/lib.rs` 内部的 `tauri::generate_handler![...]`。该列表是参考依据。主要类别：

### 核心 RPC 与诊断

| 命令                               | 用途                                                                                          |
| -------------------------------- | ------------------------------------------------------------------------------------------- |
| `core_rpc_url`                   | 返回当前活动 gateway 的 JSON-RPC URL：嵌入式核心的 `http://127.0.0.1:<port>/rpc` ，除非另一个 gateway 处于活动状态    |
| `core_rpc_token`                 | 返回当前活动 gateway 的 bearer。与 `core_rpc_url`配对：为嵌入式核心签发的令牌对容器中的核心没有意义                           |
| `core_rpc_endpoint`              | 从一个已解析的快照中同时返回 URL 和 bearer，这样在两次单独调用之间切换 gateway 时，就不会把一个 gateway 的 URL 和另一个 gateway 的令牌配对 |
| `relay_http_rpc`                 | 宿主侧 JSON-RPC POST（`{ url, token?, body }` → `{ status, body }`）用于 webview 无法获取的自托管运行时（混合内容） |
| `overlay_parent_rpc_url`         | 从父进程继承的 RPC URL（叠加窗口），来自 `OPENHUMAN_CORE_RPC_URL`                                           |
| `process_diagnostics_list_owned` | 列出由此应用 bundle 拥有的 OpenHuman 进程（macOS；其他平台为空）                                                |

使用 `app/src/services/coreRpcClient.ts` (`callCoreRpc`）来自前端。

### Gateways：在其他地方运行核心

Gateway 是到达 OpenHuman 核心的一种方式。共有四种：本进程中的核心、他人在某个 URL 上运行的核心，以及本应用自己提供的两种方式：在 Docker 容器中，或在通过 SSH 访问的机器上。后两种使用同一套代码： [tinybox](https://github.com/tinyhumansai/tinybox) models *访问* (`本地` / `ssh`）以及 *隔离* (`透传` / `docker`）作为彼此独立的两个维度，因此“构建服务器上的一个容器”是这两个选择分别作出，而不是一个有自己代码的第三种情况。

这个分界只有一行代码。gateway 会解析为一个 URL 和一个 bearer，而 `core_rpc_url` / `core_rpc_token` 从活动的那个获取响应。因此，渲染器中的每个 RPC 调用点都无需更改：前端没有按 gateway 区分的传输，而且 `services/transport/` （iOS 的 `ConnectionProfile` 路径）不参与。

配置是四次 tinybox 调用： `创建` 一个发布核心端口的 box， `启动` 在其中以分离方式启动核心，并使用新签发的 bearer， `转发` 将该已发布的端口转发回这台机器，然后轮询核心的未认证 `/health`。第三步最容易遗漏，而且缺失后也很难注意到：发布会把端口放到 *box 的* 主机上；对于 SSH 放置来说，那就是远端机器。

| 命令                 | 用途                                                    |
| ------------------ | ----------------------------------------------------- |
| `gateway_list`     | 所有已配置的 gateway，先显示内置桌面 gateway                        |
| `gateway_save`     | 添加或替换一个 gateway。不会激活它                                 |
| `gateway_delete`   | 忘记一个 gateway。正在运行的会话不受影响                              |
| `gateway_activate` | 如有需要则进行配置，然后将其设为 RPC 的目标                              |
| `gateway_active`   | 哪个 gateway 处于活动状态                                     |
| `gateway_status`   | `未激活` / `正在激活{step}` / `已连接{endpoint}` / `失败{reason}` |

记录存放在 Shell 端的 `gateways.json`中，而不是渲染器中 `localStorage`。SSH 身份路径和远程 bearer 比窗口位置敏感得多，而渲染器自己关于云令牌的说明（`utils/configPersistence.ts`）已经说明渲染器中的 XSS 可以读取其中保存的任何内容。前端保存一个 gateway *id*.

Shell 内部调用方（`imessage_scanner`, `local_data_reset`）刻意继续与嵌入式核心通信：它们涉及 *这台* 机器的 iMessage 数据库， *这台* 安装的数据，以及 *这台* 机器的音频，因此将它们路由到远程 gateway 不是不完整，而是错误的。

由 shell 本地的 `gateways` Cargo 特性（默认开启）所控制。该 gate 与下列中的特性转发规则无关： `AGENTS.md`，它们规定 Shell 在其 `openhuman-rpc` 依赖项上转发哪些核心 gate；这里没有任何内容属于 `scripts/ci/product-features.txt`.

前端： `app/src/services/gatewayService.ts`，在 设置 → 核心连接 中显示（`components/settings/panels/core/GatewaySection.tsx`).

### 核心与应用生命周期

| 命令                                                | 用途                              |
| ------------------------------------------------- | ------------------------------- |
| `start_core_process` / `restart_core_process`     | 启动/重启内嵌核心服务器任务                  |
| `recover_port_conflict` / `force_quit_port_owner` | 解决核心端口上的外部监听器                   |
| `reset_local_data`                                | 清除本地应用数据（`local_data_reset.rs`) |
| `app_quit` / `restart_app`                        | 退出或重新启动应用                       |
| `get_active_user_id`                              | 读取当前活动用户 ID                     |

### 会话（`session/`)

shell 是桌面端的会话所有者：它与 TinyHumans 后端的认证端点通信，因此核心无需这样做。 `openhuman_tinyhumans::session` 负责执行工作；shell 会将链接添加到核心（`HttpCoreLink`，同样 `（url, token）` 渲染端使用的，因此网关切换会被跟随）以及这些命令。错误带有稳定的 `前缀：` (`REJECTED`, `EXPIRED`, `TRANSIENT`, `CONSUME_FAILED`, `USER_ID_UNAVAILABLE`, `CORE`）渲染端据此分类。

| 命令                      | 用途                                                                          |
| ----------------------- | --------------------------------------------------------------------------- |
| `auth_login_with_token` | 交换一次性登录令牌（`POST /auth/login-token/consume`），验证 JWT（`GET /auth/me`），将其安装到核心中 |
| `auth_store_session`    | 安装渲染端已持有的 JWT（先验证）或离线本地令牌（连同其用户原样存储）                                        |
| `auth_logout`           | 清除核心中的会话凭据                                                                  |
| `auth_state`            | 核心的凭据状态以及缓存的当前用户                                                            |
| `auth_current_user`     | 来自 `/auth/me` 缓存（TTL 5 秒、stale-while-revalidate、退避）； `强制` 绕过缓存              |

事件： `auth://changed` （凭据或当前用户已更改；载荷 `SessionState`）以及 `auth://expired` （后端拒绝了存储的凭据，已清除；载荷 `{ source }`). `app/src/services/session/shellSessionEvents.ts` 将它们桥接到窗口事件中 `CoreStateProvider` 已经处理。

当后端不可达时，接受的 JWT（有效、subject 声明）会附带占位用户安装，并在后台重新验证；被拒绝的 JWT 永远不会安装。在云模式下，渲染端指向 shell 并不了解的远程核心，因此 `exp`，subject 声明） `pendingBackendValidation` 占位用户安装，并在后台重新验证；被拒绝的 JWT 永远不会安装。在云模式下，渲染端指向 shell 并不了解的远程核心，因此 `app/src/services/session/sessionOwner.ts` 在那里（以及在浏览器构建中）运行一个轻量的浏览器等价实现。

### 更新

`check_core_update` / `apply_core_update` （内嵌核心）以及 `check_app_update` / `download_app_update` / `install_app_update` / `apply_app_update` （桌面应用，通过 updater 插件）。

### 通知

`notification_permission_state` / `notification_permission_request` / `show_native_notification` 提供操作系统级的通知界面。它们实现在 `native_notifications`.

### 窗口管理

| 命令                                          | 用途                                              |
| ------------------------------------------- | ----------------------------------------------- |
| `activate_main_window`                      | 显示并聚焦主窗口                                        |
| `set_titlebar_for_sidebar`                  | 仅限 macOS：在侧边栏折叠时切换主窗口的标题栏样式，以便 webview 仍可铺满整个窗口 |
| `mascot_window_show` / `mascot_window_hide` | 切换吉祥物原生窗口                                       |

最小化到托盘/重新打开行为不是 IPC 命令：它位于 `RunEvent` 处理器中实现的，位于 `lib.rs` （见 [窗口和托盘行为](#window-and-tray-behavior)).

### 工件、日志、MCP、OAuth

| 命令                                                               | 用途                                                                               |
| ---------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `download_artifact_to_downloads`                                 | 将工件直接复制到 Downloads 文件夹（`artifact_commands.rs`）；没有“另存为”对话框                        |
| `pick_directory_via_dialog`                                      | 原生操作系统文件夹选择器，用于文件夹记忆源，返回一个绝对路径 a `webkitdirectory` 输入无法报告（`directory_picker.rs`) |
| `reveal_logs_folder` / `logs_folder_path`                        | 打开/返回文件日志文件夹（`file_logging.rs`)                                                  |
| `mcp_resolve_binary_path` / `mcp_open_client_config`             | MCP 客户端辅助工具（`mcp_commands.rs`)                                                   |
| `start_loopback_oauth_listener` / `stop_loopback_oauth_listener` | 本地主机 OAuth 重定向监听器（`loopback_oauth.rs`)                                           |
| `claude_code_login_launch`                                       | 启动 Claude Code 登录流程（`claude_code.rs`)                                            |

### 工作区文件链接

从 `workspace_paths.rs` 。这些命令只接受相对于工作区的路径。shell 会根据当前活动的 OpenHuman 工作区解析每个路径，将目标标准化，并在打开或读取任何内容之前拒绝路径穿越、绝对路径、类似 URI 的前缀以及符号链接逃逸。

| 命令                       | 用途                          |
| ------------------------ | --------------------------- |
| `open_workspace_path`    | 使用操作系统默认应用打开现有的工作区文件或目录。    |
| `reveal_workspace_path`  | 在操作系统文件管理器中显示现有的工作区文件或目录。   |
| `preview_workspace_text` | 从现有工作区文件中读取有上限的 UTF-8 文本预览。 |

### 合成输入主线程执行器（原生注册表，而不是 `invoke`)

注册于 `lib.rs` 在启动时，注册到 event-bus 的 native-request 方法下 `computer.input_on_main_thread` (`INPUT_ON_MAIN_THREAD_METHOD`，定义在 `openhuman_core::tools::computer::main_thread`）。这不是一个 `@tauri-apps/api` `invoke` 命令。它是核心分派给 shell 的进程内原生请求，因此合成输入会在真实的应用主线程上运行。

原因：enigo 的 macOS 键盘布局查找（`TSMGetInputSourceProperty`）会触发陷阱（`_dispatch_assert_queue_fail`, `EXC_BREAKPOINT`）并在非主线程调用时使桌面宿主崩溃。 `鼠标` / `键盘` 因此这些工具绝不会在它们的 tokio worker 上调用 enigo；它们会构建一个闭包并分派到这里，由 shell 通过 `AppHandle::run_on_main_thread`.

| 字段       | 形状                                                                                     |
| -------- | -------------------------------------------------------------------------------------- |
| 方法       | `computer.input_on_main_thread`                                                        |
| 请求       | `MainThreadInputOp { run: Box<dyn FnOnce() -> Result<String, String> + Send> }` （按值传递） |
| Response | `Result<String, String>`: `Ok(message)` 成功时 `Err(reason)` 失败时                          |
| 可用性      | 仅限桌面端。无头/CLI 构建不会注册执行器；核心调用随后会返回一个干净的 `Err`.                                           |

### 不存在的名称

以下内容在当前中不存在 `generate_handler!` 列表： `greet`, `core_rpc_relay` （被直接 `fetch` 和 `relay_http_rpc`), `ai_get_config` / `ai_refresh_config` / `write_ai_config_file`, `show_window` / `hide_window` / `toggle_window` / `minimize_window` / `maximize_window` / `close_window`，以及 `openhuman_*` 守护进程/服务辅助工具， `exchange_token`, `get_auth_state`, `socket_connect`, `start_telegram_login`. 认证和 socket 由 React 应用和核心进程处理，而不是通过这些 IPC 名称。

### 示例：核心 RPC

```typescript
import { callCoreRpc } from "../services/coreRpcClient"; // app/src/services/coreRpcClient.ts

// 直接通过 HTTP 访问内嵌核心（URL + bearer 通过
// `core_rpc_url` / `core_rpc_token` 底层解析）：
const result = await callCoreRpc({
  method: "your.rpc.method",
  params: { foo: "bar" },
});
```

***

参见 `crates/openhuman-app/src/lib.rs` (`generate_handler!`）获取完整列表。

## 核心桥接与辅助工具（`crates/openhuman-app`)

Tauri crate 不会嵌入重复的 Socket.io 服务器或 Telegram 客户端；它专注于进程内核心生命周期，以及围绕核心 JSON-RPC 接口的精简 HTTP/认证胶水。

### `CoreProcessHandle` (`core_process.rs`)

* 通过 `openhuman_rpc::host::desktop`：没有 sidecar 二进制。任务构建的运行时会在任务结束时被丢弃； `关闭` 并且启动超时中止会等待这一点后再重新拉起，因为一个进程一次只能持有一个嵌入式运行时。
* 每次启动生成一个 256 位十六进制 bearer token（`generate_rpc_token`）并将其交给嵌入式服务器；渲染端通过 `core_rpc_token` 命令读取它。
* 过期监听器策略：如果核心端口已被占用，则探测监听者是旧的 OpenHuman 核心（终止 + 重新拉起）还是其他外部进程（显示冲突）。 `OPENHUMAN_CORE_REUSE_EXISTING=1` 为调试而选择回退到附加到现有实例。
* 作为 Tauri 状态托管于 `lib.rs` (`app.manage(core_handle)`).

### `core_rpc` (`core_rpc.rs`)

* 用于宿主侧调用本地核心的共享认证辅助工具（URL 来自 `OPENHUMAN_CORE_RPC_URL` 或默认端口；bearer 来自 `core_process::current_rpc_token`).
* `relay_http_rpc` Tauri 命令：对 `openhuman_rpc::post_json_rpc` (`crates/openhuman-rpc`，特性 `http-client`的薄包装，适用于不可信来源上的自托管运行时； `bearer_header`, `redact_url_for_log` 和 `HttpRpcResponse` 从该 crate 重新导出（见 [核心 RPC 与诊断](#core-rpc-and-diagnostics)).
