mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Open existing agents from links and the CLI (#2324)
* feat(desktop): open existing agents from links Register a stable agent deep link and route it through the existing Desktop window. Add a matching CLI command that resolves the local server and activates the requested agent without creating or messaging it. * fix(desktop): recover agent link delivery
This commit is contained in:
@@ -66,6 +66,7 @@ import {
|
||||
import { registerWorkspaceRouteNavigationRef } from "@/navigation/workspace-route-navigation";
|
||||
import { ThemedStack } from "@/navigation/themed-stack";
|
||||
import { shouldUseDesktopDaemon } from "@/desktop/daemon/desktop-daemon";
|
||||
import { AgentNavigationListener } from "@/desktop/agent-navigation";
|
||||
import { listenToDesktopEvent } from "@/desktop/electron/events";
|
||||
import { updateDesktopWindowControls } from "@/desktop/electron/window";
|
||||
import { getDesktopHost } from "@/desktop/host";
|
||||
@@ -908,6 +909,7 @@ function AppShell() {
|
||||
<MobilePanelsProvider>
|
||||
<HorizontalScrollProvider>
|
||||
<OpenProjectListener />
|
||||
<AgentNavigationListener />
|
||||
<AppWithSidebar>
|
||||
<WorkspaceRouteNavigationBridge />
|
||||
<RootStack />
|
||||
|
||||
69
packages/app/src/desktop/agent-navigation.tsx
Normal file
69
packages/app/src/desktop/agent-navigation.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { useEffect } from "react";
|
||||
import { listenToDesktopEvent } from "@/desktop/electron/events";
|
||||
import { getDesktopHost } from "@/desktop/host";
|
||||
import { useStableEvent } from "@/hooks/use-stable-event";
|
||||
import { navigateToAgent } from "@/utils/navigate-to-agent";
|
||||
|
||||
interface OpenAgentEventPayload {
|
||||
serverId?: unknown;
|
||||
agentId?: unknown;
|
||||
}
|
||||
|
||||
export function AgentNavigationListener() {
|
||||
const openAgent = useStableEvent((payload: OpenAgentEventPayload | null) => {
|
||||
const serverId = typeof payload?.serverId === "string" ? payload.serverId.trim() : "";
|
||||
const agentId = typeof payload?.agentId === "string" ? payload.agentId.trim() : "";
|
||||
if (!serverId || !agentId) {
|
||||
return;
|
||||
}
|
||||
navigateToAgent({ serverId, agentId });
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const host = getDesktopHost();
|
||||
const ready = host?.agentNavigation?.ready;
|
||||
if (typeof host?.events?.on !== "function" || typeof ready !== "function") {
|
||||
return;
|
||||
}
|
||||
|
||||
let disposed = false;
|
||||
let unlisten: (() => void) | null = null;
|
||||
let retryTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
const connect = async () => {
|
||||
let dispose: (() => void) | null = null;
|
||||
try {
|
||||
dispose = await listenToDesktopEvent<OpenAgentEventPayload>("open-agent", openAgent);
|
||||
if (disposed) {
|
||||
dispose();
|
||||
return;
|
||||
}
|
||||
unlisten = dispose;
|
||||
const pending = await ready();
|
||||
if (!disposed && pending) {
|
||||
openAgent(pending);
|
||||
}
|
||||
} catch {
|
||||
dispose?.();
|
||||
if (unlisten === dispose) {
|
||||
unlisten = null;
|
||||
}
|
||||
if (!disposed) {
|
||||
retryTimer = setTimeout(() => void connect(), 1_000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void connect();
|
||||
|
||||
return () => {
|
||||
disposed = true;
|
||||
if (retryTimer) {
|
||||
clearTimeout(retryTimer);
|
||||
}
|
||||
unlisten?.();
|
||||
};
|
||||
}, [openAgent]);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -123,6 +123,10 @@ export interface DesktopEventsBridge {
|
||||
on?: (event: string, handler: (payload: unknown) => void) => Promise<() => void> | (() => void);
|
||||
}
|
||||
|
||||
export interface DesktopAgentNavigationBridge {
|
||||
ready?: () => Promise<{ serverId: string; agentId: string } | null>;
|
||||
}
|
||||
|
||||
export type DesktopBrowserShortcutEvent =
|
||||
| { browserId?: string; action: "focus-url" }
|
||||
| { browserId: string; action: "new-tab" };
|
||||
@@ -169,6 +173,7 @@ export interface DesktopHostBridge {
|
||||
platform?: string;
|
||||
invoke?: DesktopInvokeBridge["invoke"];
|
||||
getPendingOpenProject?: () => Promise<string | null>;
|
||||
agentNavigation?: DesktopAgentNavigationBridge;
|
||||
events?: DesktopEventsBridge;
|
||||
window?: DesktopWindowModuleBridge;
|
||||
dialog?: DesktopDialogBridge;
|
||||
|
||||
Reference in New Issue
Block a user