Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions apps/desktop/src/lib/trpc/routers/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { TRPCError } from "@trpc/server";
import { app } from "electron";
import { env } from "main/env.main";
import { exitImmediately } from "main/index";
import { setupSingleAgent } from "main/lib/agent-setup";
import { hasCustomRingtone } from "main/lib/custom-ringtones";
import { getHostServiceCoordinator } from "main/lib/host-service-coordinator";
import { localDb } from "main/lib/local-db";
Expand Down Expand Up @@ -1008,6 +1009,17 @@ export const createSettingsRouter = () => {
return { success: true };
}),

/**
* Re-runs wrapper/settings/hook setup for one agent. Safety net for
* the settings-UI Add flow; returns `{ ran: false }` for unknown ids.
*/
setupAgent: publicProcedure
.input(z.object({ agentId: z.string().min(1) }))
.mutation(({ input }) => {
const ran = setupSingleAgent(input.agentId);
return { ran };
}),

// TODO: remove telemetry procedures once telemetry_enabled column is dropped
getTelemetryEnabled: publicProcedure.query(() => {
return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { AgentType } from "@superset/shared/agent-command";

export type SupersetManagedBinary = AgentType | "droid";
export type SupersetManagedBinary = AgentType;

export const DESKTOP_AGENT_SETUP_ACTIONS = [
"notify-script",
Expand Down Expand Up @@ -32,7 +32,7 @@ export type DesktopAgentSetupAction =
(typeof DESKTOP_AGENT_SETUP_ACTIONS)[number];

interface DesktopAgentSetupTarget {
id: AgentType | "droid";
id: AgentType;
setupActions: readonly DesktopAgentSetupAction[];
managedBinary?: boolean;
}
Expand Down
17 changes: 17 additions & 0 deletions apps/desktop/src/main/lib/agent-setup/desktop-agent-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,20 @@ export function setupDesktopAgentCapabilities(): void {
}
}
}

/**
* Re-run setupActions for one agent. Bootstrap actions run first because
* per-agent hooks reference the shared notify script — without them the
* per-agent setup isn't self-sufficient. Returns `false` for unknown ids.
*/
export function setupSingleAgent(agentId: string): boolean {
const target = DESKTOP_AGENT_SETUP_TARGETS.find((t) => t.id === agentId);
if (!target) return false;
for (const action of DESKTOP_AGENT_SETUP_BOOTSTRAP_ACTIONS) {
DESKTOP_AGENT_SETUP_RUNNERS[action]();
}
for (const action of target.setupActions) {
DESKTOP_AGENT_SETUP_RUNNERS[action]();
}
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
return true;
}
7 changes: 6 additions & 1 deletion apps/desktop/src/main/lib/agent-setup/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import fs from "node:fs";
import { setupDesktopAgentCapabilities } from "./desktop-agent-setup";
import {
setupDesktopAgentCapabilities,
setupSingleAgent,
} from "./desktop-agent-setup";
import {
BASH_DIR,
BIN_DIR,
Expand Down Expand Up @@ -36,4 +39,6 @@ export function getSupersetBinDir(): string {
return BIN_DIR;
}

export { setupSingleAgent };

export { getCommandShellArgs, getShellArgs, getShellEnv };

This file was deleted.

This file was deleted.

15 changes: 0 additions & 15 deletions apps/desktop/src/renderer/assets/app-icons/preset-icons/codex.svg

This file was deleted.

32 changes: 0 additions & 32 deletions apps/desktop/src/renderer/assets/app-icons/preset-icons/cursor.svg

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export {
type TerminalAgentBinding,
useTerminalAgentBinding,
useTerminalAgentBindings,
} from "./useTerminalAgentBindings";
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useCallback, useMemo } from "react";
import { getHostServiceClientByUrl } from "renderer/lib/host-service-client";
import { useWorkspaceEvent } from "../useWorkspaceEvent";
import { useWorkspaceHostUrl } from "../useWorkspaceHostUrl";

type ListByWorkspaceClient = ReturnType<
typeof getHostServiceClientByUrl
>["terminalAgents"]["listByWorkspace"];
type TerminalAgentBindings = Awaited<
ReturnType<ListByWorkspaceClient["query"]>
>;
export type TerminalAgentBinding = TerminalAgentBindings[number];

/**
* Map of `terminalId → agent binding` for a workspace, read from the host
* store and invalidated on `agent:lifecycle` / `terminal:lifecycle` events.
*/
export function useTerminalAgentBindings(
workspaceId: string,
): Map<string, TerminalAgentBinding> {
const hostUrl = useWorkspaceHostUrl(workspaceId);
const queryClient = useQueryClient();
const queryKey = useMemo(
() => ["terminal-agent-bindings", hostUrl, workspaceId] as const,
[hostUrl, workspaceId],
);

const enabled = Boolean(workspaceId) && Boolean(hostUrl);

const { data } = useQuery({
queryKey,
enabled,
queryFn: () => {
if (!hostUrl) return [] as TerminalAgentBindings;
return getHostServiceClientByUrl(
hostUrl,
).terminalAgents.listByWorkspace.query({ workspaceId });
},
refetchOnWindowFocus: false,
staleTime: Number.POSITIVE_INFINITY,
});

const invalidate = useCallback(() => {
void queryClient.invalidateQueries({ queryKey });
}, [queryClient, queryKey]);

useWorkspaceEvent("agent:lifecycle", workspaceId, invalidate, enabled);
useWorkspaceEvent("terminal:lifecycle", workspaceId, invalidate, enabled);

return useMemo(() => {
const map = new Map<string, TerminalAgentBinding>();
for (const binding of data ?? []) {
map.set(binding.terminalId, binding);
}
return map;
}, [data]);
}

export function useTerminalAgentBinding(
workspaceId: string,
terminalId: string,
): TerminalAgentBinding | undefined {
const bindings = useTerminalAgentBindings(workspaceId);
return bindings.get(terminalId);
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import { BUILTIN_AGENT_LABELS } from "@superset/shared/agent-catalog";
import { TerminalSquare } from "lucide-react";
import { usePresetIcon } from "renderer/assets/app-icons/preset-icons";
import {
selectV2AgentBinding,
useV2AgentBindingStore,
} from "renderer/stores/v2-agent-bindings";
import { useTerminalAgentBinding } from "renderer/hooks/host-service/useTerminalAgentBindings";

interface TerminalPaneIconProps {
workspaceId: string;
terminalId: string;
}

/**
* Pane icon that swaps in the running agent's logo when the v2 lifecycle hook
* has detected one in this terminal. Falls back to the generic terminal glyph
* when no agent is bound or the agent id has no preset icon.
* Pane icon that swaps in the running agent's logo when the host-service
* `terminalAgents` tracker has detected one in this terminal. Falls back
* to the generic terminal glyph when no agent is bound or the agent id
* has no preset icon.
*/
export function TerminalPaneIcon({ terminalId }: TerminalPaneIconProps) {
const binding = useV2AgentBindingStore(selectV2AgentBinding(terminalId));
const agentId = binding?.identity.agentId;
export function TerminalPaneIcon({
workspaceId,
terminalId,
}: TerminalPaneIconProps) {
const binding = useTerminalAgentBinding(workspaceId, terminalId);
const agentId = binding?.agentId;
const iconSrc = usePresetIcon(agentId ?? "");

if (agentId && iconSrc) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ export function TerminalSessionDropdown({
onMouseDown={(event) => event.stopPropagation()}
onClick={(event) => event.stopPropagation()}
>
<TerminalPaneIcon terminalId={terminalId} />
<TerminalPaneIcon workspaceId={workspaceId} terminalId={terminalId} />
{workspaceRunState && (
<span
className={
Expand Down
Loading
Loading