mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-14 04:30:51 +08:00
[feat] bundle MCP and DSH into one installable package
This commit is contained in:
1 parent
02a25a759f
commit
2a9faf1eb1
15 files changed
+875
-590
No files matched your search
@@ -1,44 +1,42 @@
|
||||
# CrossDesk Sidebar for DeepSeek Harness
|
||||
# 在 DeepSeek Harness 中使用 CrossDesk
|
||||
|
||||
在 DeepSeek Harness **桌面版**中,自动将 CrossDesk MCP 返回的页面打开到发起调用的会话侧栏。适配 Harness 0.2.2-rc.1 的 Sidebar Browser 和 Connection 接口。浏览器版的 iframe 不在支持范围内。
|
||||
安装 CrossDesk 插件后,你可以让 Agent 操作远程电脑,并在当前对话的右侧浏览器监看画面。
|
||||
|
||||
## 安装
|
||||
|
||||
先按 [DSH 完整安装指南](../../README.md#install-dsh) 安装 CrossDesk MCP 和兼容的原生 CLI,并注册名为 `crossdesk` 的 MCP 服务。**本插件不会自动注册 MCP 服务**;服务配置和插件安装缺一不可。
|
||||
1. 按 [下载安装包](../../README.md#install-package) 选择与你的本机系统和芯片匹配的平台包,解压 ZIP 并取出 `.tgz` 文件。
|
||||
2. 在 Harness 桌面版的插件页面安装该文件,或执行以下命令。将示例中的路径和版本号替换为实际文件:
|
||||
|
||||
使用 MCP 本地安装包时,插件及构建产物已包含在包内:
|
||||
```sh
|
||||
dsh plugin --profile desktop add "/absolute/path/chunkdash-crossdesk-mcp-0.1.0.tgz"
|
||||
```
|
||||
|
||||
3. 重启 Harness,确认 CrossDesk 插件已启用。
|
||||
|
||||
平台包已经包含所需的原生程序,并自动提供 MCP 工具和侧栏画面。安装时需要联网下载依赖。终端找不到 `dsh` 时,可直接使用插件页面,或按 [完整安装指南](../../README.md#install-dsh) 使用应用自带的命令。
|
||||
|
||||
## 连接并使用
|
||||
|
||||
在对话中发送:
|
||||
|
||||
> 打开 CrossDesk,让我选择远程电脑。
|
||||
|
||||
在右侧面板输入远端设备 ID 和访问密码。需要 Agent 操作远端时选择 **允许 Agent 操作**,然后点击 **授权并连接**。看到远端桌面后,即可下达任务,例如:
|
||||
|
||||
> 在远程电脑的浏览器中搜索天气。
|
||||
|
||||
密码只在面板中输入。需要停止操作时点击 **暂停 Agent**;结束使用时,在 **会话选项** 中选择 **断开连接**。关闭侧栏本身不会断开远端连接。
|
||||
|
||||
保存设备、自动连接、人工接管和声音的用法见 [用户指南](../../README.md#用户连接流程)。如果没有工具或画面,请查看 [常见问题](../../README.md#install-troubleshooting)。
|
||||
|
||||
## 更新与卸载
|
||||
|
||||
通过插件页面安装新版平台包后重启 Harness。卸载也可在插件页面完成,或执行:
|
||||
|
||||
```sh
|
||||
dsh plugin --profile desktop add /absolute/path/crossdesk-mcp/node_modules/@chunkdash/crossdesk-mcp/integrations/deepseek-harness
|
||||
dsh plugin --profile desktop remove @chunkdash/crossdesk-mcp
|
||||
```
|
||||
|
||||
从源码运行时,先构建 MCP,再安装工程中的插件目录:
|
||||
卸载后,保存在本机的设备配置和系统凭据仍会保留。
|
||||
|
||||
```sh
|
||||
npm --prefix /absolute/path/crossdesk/apps/mcp run build
|
||||
dsh plugin --profile desktop add /absolute/path/crossdesk/apps/mcp/integrations/deepseek-harness
|
||||
```
|
||||
|
||||
也可在 Harness 的插件页面通过本地路径安装。重启 Harness 和 CrossDesk MCP 后,确认 `crossdesk-sidebar` 组件启用并运行。MCP 的 YAML 配置、源码运行所需的 `--native-binary`、首次连接及排查步骤均见上述完整指南。该包只增加侧栏适配,不连接设备、不修改设备授权。
|
||||
|
||||
不要强制使用 `--panel=apps` 或 `--browser-launch=system`;保留默认 `auto`,或显式使用 `--panel=browser --browser-launch=host`。若服务名称不同,在 Harness profile 的 `cordis.patch.yml` 中添加:
|
||||
|
||||
```yaml
|
||||
- id: crossdesk-sidebar
|
||||
config:
|
||||
serverName: your_crossdesk_server_name
|
||||
```
|
||||
|
||||
## 行为与边界
|
||||
|
||||
- 宿主插件只接收指定 MCP 名称的 `crossdesk_open`、`crossdesk_connect`、`crossdesk_open_browser`、`crossdesk_unlock` 成功结果,验证页面类型及 `127.0.0.1` 启动地址。
|
||||
- 通过 Harness 已认证的 Connection 接口交接页面请求;客户端约每 750 毫秒检查当前会话,只在发起调用的会话中打开侧栏,不读取聊天记录或重新执行工具。
|
||||
- 页面请求在内存中最多保存 60 秒,具有多窗口领取租约及确认机制。相同视图重新签发时替换插件打开的旧标签;切换会话、卸载、过期后不重放历史启动地址。
|
||||
- 地址仅用于导航,不抓取启动页、复制配对令牌或代理视频。CrossDesk 继续使用本机 WebSocket / WebCodecs 播放和现有设备授权;插件不声明页面已经配对或视频已就绪,Agent 仍通过 `crossdesk_get_session` 确认。
|
||||
- Harness 网页版未启用此桥接,因为其 iframe 不能嵌入受保护的 CrossDesk 页面。不会放宽 CrossDesk 的 Origin、CSP、Cookie 或 `X-Frame-Options` 策略。
|
||||
|
||||
该插件与 MCP 一起构建,产物位于本目录的 `dist/`。卸载使用 `dsh plugin --profile desktop remove @chunkdash/dsh-crossdesk-sidebar`。
|
||||
|
||||
2026-11-12 已在 macOS / DeepSeek Harness 0.2.2-rc.1 验证自动打开、配对及 1920 × 1080、约 27–29 FPS 的实时播放;远端为已授权的 Mac mini,仅查看模式。
|
||||
|
||||
宿主接口参考:[Sidebar Browser](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-sidebar-browser)、[Right Sidebar](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-sidebar-right)、[Connection](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/connection)。
|
||||
源码构建和集成机制见 [开发参考](../../DEVELOPMENT.md#harness-development)。
|
||||
@@ -0,0 +1,39 @@
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { isAbsolute } from "node:path";
|
||||
import z from "@deepseek-ai/schemastery";
|
||||
import { Config as McpConfig, apply as applyMcp } from "@deepseek-ai/dsh-mcp-client";
|
||||
import { nativeBinary } from "../../../dist/native.js";
|
||||
import { apply as applySidebar } from "./host.js";
|
||||
|
||||
export const name = "crossdesk";
|
||||
export const inject = ["tools", "connection"];
|
||||
export const Config = z.object({
|
||||
serverName: z.string().pattern(/^[a-zA-Z0-9_-]{1,24}$/).default("crossdesk"),
|
||||
nativeBinary: z.string(),
|
||||
configDir: z.string(),
|
||||
});
|
||||
|
||||
// Built into dist/harness.js beside the ordinary MCP entry. DSH supplies its
|
||||
// own MCP client and Node/Electron executable; no PATH or profile edits needed.
|
||||
export async function apply(ctx, config) {
|
||||
for (const field of ["nativeBinary", "configDir"])
|
||||
if (config[field] !== undefined && !isAbsolute(config[field]))
|
||||
throw new Error(`CrossDesk ${field} must be an absolute path`);
|
||||
let binary;
|
||||
try { binary = await nativeBinary(config.nativeBinary); }
|
||||
catch (error) {
|
||||
throw new Error("CrossDesk native CLI is unavailable or incompatible. Install the platform bundle with the native CLI included, or set nativeBinary for a source build.", { cause: error });
|
||||
}
|
||||
const args = [fileURLToPath(new URL("./main.js", import.meta.url)), "serve", "--stdio",
|
||||
"--panel=browser", "--browser-launch=host", "--native-binary", binary];
|
||||
if (config.configDir) args.push("--config-dir", config.configDir);
|
||||
// Reuse the host's client implementation so namespace reservation, tool
|
||||
// permissions, images, reconnect and awaited disposal have a single owner.
|
||||
// Duplicate legacy MCP entries are rejected before another server is spawned.
|
||||
await applyMcp(ctx, McpConfig({
|
||||
serverName: config.serverName, transport: "stdio", command: process.execPath, args,
|
||||
env: process.versions.electron ? { ELECTRON_RUN_AS_NODE: "1" } : {},
|
||||
toolCallTimeoutMs: 90000, failOnStartupError: true,
|
||||
}));
|
||||
applySidebar(ctx, { serverName: config.serverName });
|
||||
}
|
||||
Reference in new issue
Block a user