multica/apps/desktop
Jiang Bohan cea3336256 docs(desktop): update TODO list with core improvements
Remove completed items (device authorization, tools testing, token verification).
Add new priorities:
- Memory tool and memory.md unification
- Profile loading optimization (truncation)
- Agent self-iteration capability
- Local IPC direct communication mode

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:59:52 +08:00
..
electron Merge pull request #79 from multica-ai/feat/agent-style-setting 2026-02-04 14:48:29 +08:00
src Merge pull request #79 from multica-ai/feat/agent-style-setting 2026-02-04 14:48:29 +08:00
.eslintrc.cjs feat(desktop): scaffold Electron app with Vite 2026-01-30 11:34:09 +08:00
.gitignore feat(desktop): initialize electron app with routing and cleanup 2026-02-03 14:17:31 +08:00
electron-builder.json5 feat(desktop): scaffold Electron app with Vite 2026-01-30 11:34:09 +08:00
index.html feat(desktop): initialize electron app with routing and cleanup 2026-02-03 14:17:31 +08:00
package.json feat(desktop): integrate Chat component into desktop app 2026-02-03 20:08:30 +08:00
README.md docs(desktop): update TODO list with core improvements 2026-02-04 14:59:52 +08:00
tsconfig.json fix(desktop): resolve TypeScript build errors 2026-02-03 19:26:25 +08:00
tsconfig.node.json feat(desktop): scaffold Electron app with Vite 2026-01-30 11:34:09 +08:00
vite.config.ts chore(desktop): add dependencies for routing and QR code 2026-02-03 18:25:52 +08:00

Multica Desktop App 设计文档

产品定位

Multica Desktop 是一个统一的桌面应用,具有双重身份:

  1. Host 模式: 本机运行 Hub + Agent可供其他设备连接
  2. Client 模式: 连接到其他 Hub 的 Agent 进行对话

用户安装同一个 App既可以作为 Agent 的宿主(让其他设备扫码连接),也可以扫码连接到别人的 Agent。

架构图

┌─────────────────────────────────────────────────────────────────────────────┐
│                           Multica Desktop App                                │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                         React UI (Renderer)                          │   │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  │   │
│  │  │  Home   │  │  Chat   │  │  Tools  │  │ Skills  │  │Settings │  │   │
│  │  └─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘  │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                    │                                         │
│                    ┌───────────────┴───────────────┐                        │
│                    │                               │                        │
│              直接调用 (本地)              WebSocket (远程)                   │
│                    │                               │                        │
│                    ▼                               ▼                        │
│  ┌─────────────────────────────┐     ┌─────────────────────────────┐       │
│  │    Local Hub + Agent        │     │   Remote Hub (via Gateway)   │       │
│  │    (进程内)                  │     │   (另一台设备)               │       │
│  └─────────────────────────────┘     └─────────────────────────────┘       │
└─────────────────────────────────────────────────────────────────────────────┘
                                              │
                                              │ WebSocket
                                              ▼
                                    ┌─────────────────────┐
                                    │      Gateway        │
                                    │   (公网 WebSocket)  │
                                    └─────────────────────┘

关键点:

  • 统一应用: 不区分 Admin App 和 Client App一个 App 两种用法
  • Chat 双模式: Chat 页面可以选择与本地 Agent 对话,或连接远程 Agent 对话
  • 本地 Agent: Hub + Agent 跑在 Electron 主进程内UI 通过 IPC 调用访问
  • 远程连接: 通过 Gateway WebSocket 连接到其他设备的 Hub

约束: 第一阶段 1 Client - 1 Hub - 1 Agent Session


技术实现设计

技术栈

层级 技术 说明
框架 Electron 30 桌面应用
前端 React 19 + Vite 渲染进程
路由 react-router-dom v7 HashRouter
状态 @multica/store (Zustand) 复用现有 store
UI @multica/ui (Shadcn) 复用现有组件
二维码 qrcode.react 生成二维码
通信 @multica/sdk Gateway 连接

文件结构规划

apps/desktop/
├── electron/
│   ├── main.ts           # 主进程 (Hub + Agent)
│   └── preload.ts        # 预加载脚本 (如需 IPC)
├── src/
│   ├── main.tsx          # React 入口
│   ├── App.tsx           # 路由配置
│   ├── pages/
│   │   ├── home.tsx      # Home 入口页 (三个选项)
│   │   ├── chat.tsx      # Chat 页面 (Local/Remote 双模式)
│   │   ├── tools.tsx     # Tools 管理页
│   │   ├── skills.tsx    # Skills 管理页
│   │   └── layout.tsx    # 全局布局 (Header + Tabs)
│   ├── components/
│   │   ├── qr-code.tsx           # 二维码组件
│   │   ├── qr-scanner.tsx        # 扫码组件
│   │   ├── connection-status.tsx # 连接状态
│   │   ├── tool-list.tsx         # Tools 列表
│   │   └── skill-list.tsx        # Skills 列表
│   └── hooks/
│       ├── use-local-agent.ts    # 本地 Agent 管理
│       ├── use-remote-agent.ts   # 远程 Agent 连接
│       └── use-connection.ts     # 连接状态管理
└── package.json

核心实现点

1. 二维码生成与连接

二维码内容格式:

{
   "type": "multica-connect",
   "gateway": "wss://gateway.multica.ai",
   "hubId": "019c1d32-xxxx",
   "agentId": "019c1d32-yyyy",
   "token": "random-uuid-token",
   "expires": 1234567890
}

连接流程:

1. Admin 启动 → Hub 连接公网 Gateway → 注册为 deviceType: "hub"
2. Admin 创建 Agent → 生成 token → 编码到二维码 (含 hubId + agentId + token)
3. Client 扫码 → 解析二维码 → 连接同一 Gateway
4. Client 发送 "connect-request" 到 hubId (带 token)
5. Admin 验证 token 有效且未过期 → 建立配对关系
6. Client 后续消息发到 hubIdpayload 带 agentId
7. Hub 路由消息到对应 Agent

2. Tools 管理

现有 CLI 命令 (已实现):

multica tools list                    # 列出所有 tools
multica tools list --profile coding   # 按 profile 过滤
multica tools groups                  # 显示 tool groups
multica tools profiles                # 显示预设 profiles

Admin App 实现方式 - 通过 IPC 调用 Main Process:

// Renderer 进程 (React Hook)
const tools = await window.electronAPI.tools.list();
const groups = await window.electronAPI.tools.getGroups();
const profiles = await window.electronAPI.tools.getProfiles();
await window.electronAPI.tools.setStatus('exec', false);

// Main 进程 (IPC Handler)
ipcMain.handle('tools:list', async () => {
   const allTools = createAllTools(process.cwd());
   return allTools.map((t) => ({
      name: t.name,
      group: TOOL_GROUPS[t.name],
      enabled: true,
   }));
});

注意: Renderer 进程运行在沙盒中,不能直接访问 Node.js API必须通过 IPC 调用 Main Process。

3. Skills 管理

现有 CLI 命令 (已实现):

multica skills list                   # 列出所有 skills
multica skills status                 # 显示状态摘要
multica skills status <id>            # 单个 skill 详情
multica skills add owner/repo         # 从 GitHub 添加
multica skills remove <name>          # 删除 skill
multica skills install <id>           # 安装依赖

Admin App 实现方式 - 通过 IPC 调用 Main Process:

// Renderer 进程 (React Hook)
const skills = await window.electronAPI.skills.list();
await window.electronAPI.skills.add('anthropics/skills');
await window.electronAPI.skills.remove('pdf');
await window.electronAPI.skills.setEnabled('commit', false);

// Main 进程 (IPC Handler)
ipcMain.handle('skills:list', async () => {
   return await listAllSkillsWithStatus();
});
ipcMain.handle('skills:add', async (_, source: string) => {
   await addSkill({ source, force: false });
});

三、实现优先级

Phase 1: 基础框架 (MVP)

  1. Layout 组件 - Header + Tabs 导航
  2. Home 页面 - 二维码显示 + 连接状态
  3. Gateway 连接 - 复用 @multica/store

Phase 2: 管理功能

  1. Tools 页面 - 列表展示 + 开关切换
  2. Skills 页面 - 列表展示 + 基础操作
  3. Settings - Gateway URL + Theme

Phase 3: 完善体验

  1. Agent 页面 - 状态监控 + Provider 切换
  2. 二维码刷新机制
  3. 错误处理 + Toast 提示

四、Hub 集成技术方案

架构概述

Desktop App 采用 Electron IPC + Hub 实例 架构:

┌─────────────────────────────────────────────────────────────────────────────┐
│                           Electron Desktop App                               │
│                                                                             │
│  ┌────────────────────────────────────────────────────────────────────────┐ │
│  │                     Renderer Process (React UI)                         │ │
│  │                                                                        │ │
│  │   home.tsx  →  useHub()  →  window.electronAPI.hub.getStatus()        │ │
│  │   tools.tsx →  useTools() → window.electronAPI.tools.list()           │ │
│  │   skills.tsx→  useSkills()→ window.electronAPI.skills.list()          │ │
│  │                                                                        │ │
│  └──────────────────────────────┬─────────────────────────────────────────┘ │
│                                 │ IPC (contextBridge)                       │
│                                 ▼                                           │
│  ┌────────────────────────────────────────────────────────────────────────┐ │
│  │                      Main Process (Node.js)                             │ │
│  │                                                                        │ │
│  │   ┌──────────────────────────────────────────────────────────────┐    │ │
│  │   │                    Hub Instance                               │    │ │
│  │   │  - hubId: UUIDv7                                             │    │ │
│  │   │  - agents: Map<agentId, AsyncAgent>                          │    │ │
│  │   │  - status: 'starting' | 'ready' | 'error'                    │    │ │
│  │   │  - GatewayClient: 连接公网 Gateway (可选)                     │    │ │
│  │   └──────────────────────────────────────────────────────────────┘    │ │
│  │                                │                                       │ │
│  │   ┌────────────────────────────▼────────────────────────────────┐     │ │
│  │   │                  AsyncAgent Instance                         │     │ │
│  │   │  - agentId: UUIDv7                                          │     │ │
│  │   │  - runner: AgentRunner (LLM interaction)                    │     │ │
│  │   │  - tools: Tool[] (可动态更新)                                │     │ │
│  │   │  - skills: SkillInfo[]                                      │     │ │
│  │   └─────────────────────────────────────────────────────────────┘     │ │
│  │                                                                        │ │
│  └────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    │ WebSocket (可选,用于 Client 远程连接)
                                    ▼
                          ┌─────────────────────┐
                          │  Public Gateway     │
                          │  (wss://xxx)        │
                          └─────────────────────┘

IPC 通信机制

工作原理:

  1. Main Process: 在 Electron 主进程中创建 Hub 和 Agent 实例
  2. Preload Script: 通过 contextBridge.exposeInMainWorld 暴露安全 API
  3. Renderer Process: React UI 通过 window.electronAPI 调用主进程功能

与 CLI 命令的关系:

CLI 命令 IPC Handler 底层调用
multica tools list tools:list createAllTools() + getToolStatus()
multica tools enable xxx tools:setStatus setToolStatus()
multica skills list skills:list loadSkills() + listAllSkillsWithStatus()
multica skills add xxx skills:add addSkill()

本质上 CLI 和 Admin App 调用的是同一套底层模块,区别仅在于:

  • CLI: 通过命令行参数解析后直接调用
  • Admin App: 通过 IPC 转发调用

核心文件

apps/desktop/
├── electron/
│   ├── main.ts                 # 主进程入口,创建窗口 + 注册 IPC
│   ├── preload.ts              # 暴露 electronAPI
│   └── ipc/
│       ├── index.ts            # 统一注册所有 IPC handlers
│       ├── hub.ts              # Hub 管理 (创建/状态/连接 Gateway)
│       ├── agent.ts            # Agent 管理 (Tools 读写)
│       └── skills.ts           # Skills 管理
├── src/
│   └── hooks/
│       ├── use-hub.ts          # 获取 Hub 状态
│       ├── use-tools.ts        # Tools CRUD
│       └── use-skills.ts       # Skills CRUD

IPC 接口定义

// electron/preload.ts 暴露的 API
interface ElectronAPI {
   hub: {
      getStatus: () => Promise<HubStatus>;
      getAgentInfo: () => Promise<AgentInfo | null>;
   };
   tools: {
      list: () => Promise<ToolStatus[]>;
      setStatus: (toolName: string, enabled: boolean) => Promise<void>;
      getGroups: () => Promise<Record<string, string[]>>;
      getProfiles: () => Promise<string[]>;
   };
   skills: {
      list: () => Promise<SkillInfo[]>;
      add: (source: string) => Promise<void>;
      remove: (name: string) => Promise<void>;
      setEnabled: (name: string, enabled: boolean) => Promise<void>;
   };
}

// 类型定义
interface HubStatus {
   hubId: string;
   status: 'starting' | 'ready' | 'error';
   agentCount: number;
   gatewayConnected: boolean;
   gatewayUrl?: string;
}

interface AgentInfo {
   agentId: string;
   provider: string;
   model: string;
   status: 'idle' | 'running';
}

interface ToolStatus {
   name: string;
   group: string;
   enabled: boolean;
   needsConfig?: boolean;
}

interface SkillInfo {
   name: string;
   command: string;
   source: 'bundled' | 'global' | 'profile';
   status: 'ready' | 'missing-deps' | 'disabled';
   description?: string;
}

Hub 生命周期

// electron/ipc/hub.ts 简化逻辑

let hub: Hub | null = null;

export function registerHubHandlers(ipcMain: IpcMain) {
   // App 启动时自动创建 Hub
   ipcMain.handle('hub:getStatus', async () => {
      if (!hub) {
         hub = new Hub();
         await hub.start();
         // 创建默认 Agent
         const agent = await hub.createAgent({
            provider: credentialManager.getLlmProvider(),
            model: credentialManager.getLlmProviderConfig()?.model,
         });
      }
      return {
         hubId: hub.id,
         status: hub.status,
         agentCount: hub.agents.size,
         gatewayConnected: hub.gateway?.connected ?? false,
      };
   });
}

Tools 实时更新机制

当用户在 UI 中切换 Tool 开关时:

1. UI: Switch onChange → useTools.setToolStatus('exec', false)
2. Hook: await window.electronAPI.tools.setStatus('exec', false)
3. IPC: ipcMain.handle('tools:setStatus') → agent.updateTools(...)
4. Agent: 重新过滤 tools 列表,下次 LLM 调用使用新配置

注意: Tools 状态目前保存在内存中,重启后重置。后续可持久化到 ~/.super-multica/tool-config.json


六、关于 RPC 与 IPC 的区别

: Admin UI 和 Hub/Agent 之间是通过什么方式通信?

: 通过 Electron IPC (进程间通信),不是网络 RPC。

通信类型 场景 协议
IPC Admin UI ↔ Hub (同一设备) Electron IPC (内存)
RPC Client ↔ Gateway ↔ Hub (跨设备) WebSocket

为什么选择 IPC 而不是直接 import?

  1. 安全隔离: Renderer 进程不应直接访问 Node.js API 和文件系统
  2. 进程隔离: Electron 推荐 Renderer 运行在沙盒中
  3. 一致性: 与 CLI 调用相同的底层模块,便于维护
  4. 扩展性: 后续可以轻松添加 RPC 支持,供远程管理
┌─────────────────────────────────────────────────────────────────┐
│                       Electron App                               │
│                                                                 │
│  ┌──────────────────────┐      ┌─────────────────────────────┐ │
│  │  Renderer Process    │      │     Main Process            │ │
│  │  (React UI, 沙盒)    │      │     (Node.js, 完整权限)      │ │
│  │                      │ IPC  │                             │ │
│  │  useTools() ──────────────► │  ipcMain.handle('tools:*')  │ │
│  │  useSkills() ─────────────► │  ipcMain.handle('skills:*') │ │
│  │  useHub() ────────────────► │  Hub + Agent 实例           │ │
│  └──────────────────────┘      └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

IPC 调用示例:

// Renderer (React 组件)
const tools = await window.electronAPI.tools.list();

// Main Process (IPC Handler)
ipcMain.handle('tools:list', async () => {
   const allTools = createAllTools(process.cwd());
   return allTools.map((t) => ({
      name: t.name,
      group: TOOL_GROUPS[t.name] || 'other',
      enabled: getToolStatus(t.name),
   }));
});

七、依赖安装

# 二维码生成
pnpm --filter @multica/desktop add qrcode.react

# 类型定义 (如需要)
pnpm --filter @multica/desktop add -D @types/qrcode.react

八、待办事项

核心功能

Memory 统一

  • 统一 memory tool (key-value JSON) 和 memory.md 的逻辑
  • 考虑支持 OpenClaw 风格的 MEMORY.md + 语义搜索

Profile 加载优化

  • 参考 OpenClaw 的截断策略(超过 20k 字符时保留 head 70% + tail 20%
  • 子 Agent 只加载必要的 bootstrap 文件

Agent 自我迭代

  • Agent 需要有自己迭代 Profile 的能力(更新 soul.md、user.md 等)
  • 支持 Agent 主动记忆用户偏好

本地直连模式

  • 增加通过 IPC 的方式与同一 Electron 进程里的 Agent 直接通讯
  • 本地对话不需要走 Gateway 授权流程

体验优化

Settings 页面

  • Gateway URL 配置
  • Theme 切换 (Light / Dark / System)
  • 打开 credentials.json5 按钮