From 50c17145afdccf8b7bd3b0387083d1714309b8de Mon Sep 17 00:00:00 2001 From: Satya Patel Date: Wed, 29 Apr 2026 10:11:24 -0700 Subject: [PATCH 01/12] fix(desktop): give v2 chat pane full width (#3859) The v2 ChatPaneInterface root sat inside PaneContent's row-direction flex with no width directive, so it sized to its intrinsic content and the chat appeared smushed. Add w-full to match every other v2 pane; also restore w-full on the SessionSelector trigger button. --- .../ChatPane/components/SessionSelector/SessionSelector.tsx | 2 +- .../components/WorkspaceChatInterface/ChatPaneInterface.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/SessionSelector/SessionSelector.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/SessionSelector/SessionSelector.tsx index eeccd16f790..cbccee3a151 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/SessionSelector/SessionSelector.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/usePaneRegistry/components/ChatPane/components/SessionSelector/SessionSelector.tsx @@ -116,7 +116,7 @@ export function SessionSelector({ ) : ( @@ -113,6 +128,7 @@ export function OrganizationDropdown({ {displayName} + {planBadge} ); diff --git a/apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx b/apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx index 62f852b53c2..243db056bb1 100644 --- a/apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx +++ b/apps/web/src/app/(agents)/components/AgentsHeader/AgentsHeader.tsx @@ -1,7 +1,9 @@ "use client"; import { authClient } from "@superset/auth/client"; +import { isPaidPlan } from "@superset/shared/billing"; import { Avatar, AvatarFallback, AvatarImage } from "@superset/ui/avatar"; +import { Badge } from "@superset/ui/badge"; import { Drawer, DrawerContent, DrawerTitle } from "@superset/ui/drawer"; import { DropdownMenu, @@ -44,6 +46,14 @@ export function AgentsHeader() { trpc.user.myOrganizations.queryOptions(), ); + const { data: activePlan } = useQuery(trpc.billing.activePlan.queryOptions()); + + const isPro = isPaidPlan(activePlan?.plan); + const planLabel = + isPro && activePlan?.plan + ? activePlan.plan.charAt(0).toUpperCase() + activePlan.plan.slice(1) + : null; + const user = session?.user; const activeOrganizationId = session?.session?.activeOrganizationId; const activeOrganization = organizations?.find( @@ -191,7 +201,14 @@ export function AgentsHeader() { Account menu
-

{user?.name}

+
+

{user?.name}

+ {isPro && ( + + {planLabel} + + )} +

{user?.email}

@@ -251,7 +268,14 @@ export function AgentsHeader() {
-

{user?.name}

+
+

{user?.name}

+ {isPro && ( + + {planLabel} + + )} +

{user?.email}

diff --git a/packages/trpc/src/router/billing/billing.ts b/packages/trpc/src/router/billing/billing.ts index 3616f241006..664f17daf29 100644 --- a/packages/trpc/src/router/billing/billing.ts +++ b/packages/trpc/src/router/billing/billing.ts @@ -1,8 +1,9 @@ import { stripeClient } from "@superset/auth/stripe"; import { db } from "@superset/db/client"; import { members, subscriptions } from "@superset/db/schema"; +import { ACTIVE_SUBSCRIPTION_STATUSES } from "@superset/shared/billing"; import { TRPCError, type TRPCRouterRecord } from "@trpc/server"; -import { and, eq } from "drizzle-orm"; +import { and, desc, eq, inArray } from "drizzle-orm"; import type Stripe from "stripe"; import { z } from "zod"; import { env } from "../../env"; @@ -65,6 +66,25 @@ async function requireOwnerWithCustomer(ctx: { } export const billingRouter = { + activePlan: protectedProcedure.query(async ({ ctx }) => { + const activeOrgId = ctx.activeOrganizationId; + if (!activeOrgId) return { plan: "free" as const, status: null }; + + const subscription = await db.query.subscriptions.findFirst({ + where: and( + eq(subscriptions.referenceId, activeOrgId), + inArray(subscriptions.status, ACTIVE_SUBSCRIPTION_STATUSES), + ), + orderBy: desc(subscriptions.createdAt), + }); + + if (!subscription) { + return { plan: "free" as const, status: null }; + } + + return { plan: subscription.plan, status: subscription.status }; + }), + invoices: protectedProcedure.query(async ({ ctx }) => { const activeOrgId = ctx.activeOrganizationId; if (!activeOrgId) { From 2faa5983b4ca9c129c0a82f65e40f2c191e8b2a4 Mon Sep 17 00:00:00 2001 From: Kiet <31864905+Kitenite@users.noreply.github.com> Date: Wed, 29 Apr 2026 10:01:50 -0700 Subject: [PATCH 11/12] fix(host-service): clean up exited terminals on workspace delete (#3856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `disposeSessionsByWorkspaceId` filtered by `status = "active"`, so any session whose row had drifted to `exited` (e.g. via `pty.onExit`) was skipped on workspace deletion — leaving the in-memory `sessions` Map entry behind. Widen to `status != "disposed"` so zombie rows get disposed too. `disposeSession` is already idempotent against a dead PTY. --- packages/host-service/src/terminal/terminal.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/host-service/src/terminal/terminal.ts b/packages/host-service/src/terminal/terminal.ts index cf44c550440..61681ddb408 100644 --- a/packages/host-service/src/terminal/terminal.ts +++ b/packages/host-service/src/terminal/terminal.ts @@ -12,7 +12,7 @@ import { scanForTerminalTitle, type TerminalTitleScanState, } from "@superset/shared/terminal-title-scanner"; -import { and, eq } from "drizzle-orm"; +import { and, eq, ne } from "drizzle-orm"; import type { Hono } from "hono"; import { type IPty, spawn } from "node-pty"; import type { HostDb } from "../db"; @@ -307,7 +307,7 @@ export function disposeSessionsByWorkspaceId( .where( and( eq(terminalSessions.originWorkspaceId, workspaceId), - eq(terminalSessions.status, "active"), + ne(terminalSessions.status, "disposed"), ), ) .all(); From d19d9a0a75e36ec3c774aa125e555d50e33541c6 Mon Sep 17 00:00:00 2001 From: Kiet <31864905+Kitenite@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:34:53 -0700 Subject: [PATCH 12/12] fix(agents): correct copilot flag order and mastracode prompt mode (#3869) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(agents): correct copilot flag order and mastracode prompt mode - copilot: reorder `promptCommand` from `copilot -i --allow-tool=write` to `copilot --allow-tool=write -i`. With the old order, the rendered shell command landed as `copilot -i --allow-tool=write "PROMPT"`, which commander.js parsed as `-i=--allow-tool=write` and rejected the prompt with `error: too many arguments`. - mastracode: add `promptCommand: "mastracode --prompt"`. The previous default-from-`command` rendered `mastracode "PROMPT"`, but mastracode's TUI silently drops positional args (only the headless `--prompt`/`-p` path actually executes the input). Trade-off: prompt-mode now runs headless since upstream has no `interactive + auto-execute` flag like copilot's `-i` or gemini's `--prompt-interactive`. - bump `mastracode` desktop dep `0.15.0-alpha.3` → `0.16.0` to match the current published release. * fix(agents): keep mastracode interactive after handling prompt Chain headless prompt execution with a TUI relaunch so the user lands in an interactive session on the same thread the prompt seeded. Without the suffix, `mastracode --prompt` executed and exited, breaking the expected "interactive + handles prompt" UX. The TUI auto-resumes the most recent thread (per mastracode 0.13+ behavior), so chaining `; mastracode` after the headless run drops the user back into the conversation populated by the prompt. * fix(agents): fix copilot flag order in legacy permissions migration The migration backfill restored `copilot -i --allow-all` for users seeded before #3546, which has the same flag-ordering bug as the registry: `-i` consumes `--allow-all` as its prompt value and the real prompt heredoc errors with `too many arguments`. Reorder to `copilot --allow-all -i` so the prompt lands directly after `-i`. The yolo permissions intent is preserved via the unchanged suffix. * fix(desktop): revert internal mastracode bump to align workspace versions sherif flagged the workspace mismatch — packages/chat and packages/host-service still pin 0.15.0-alpha.3, so bumping desktop alone broke multi-version consistency. The runtime upgrade is already covered by the user-installed CLI; the internal dep just needs to track the rest of the workspace. --- packages/shared/src/agent-permissions-migration.ts | 2 +- packages/shared/src/builtin-terminal-agents.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/agent-permissions-migration.ts b/packages/shared/src/agent-permissions-migration.ts index cda447361c9..2066603cba8 100644 --- a/packages/shared/src/agent-permissions-migration.ts +++ b/packages/shared/src/agent-permissions-migration.ts @@ -41,7 +41,7 @@ export const LEGACY_BUILTIN_TERMINAL_AGENT_OVERRIDES: Readonly< }, copilot: { command: "copilot --allow-all", - promptCommand: "copilot -i --allow-all", + promptCommand: "copilot --allow-all -i", promptCommandSuffix: "--yolo", }, "cursor-agent": { diff --git a/packages/shared/src/builtin-terminal-agents.ts b/packages/shared/src/builtin-terminal-agents.ts index b634fe09179..a06d9ede7d8 100644 --- a/packages/shared/src/builtin-terminal-agents.ts +++ b/packages/shared/src/builtin-terminal-agents.ts @@ -100,6 +100,8 @@ export const BUILTIN_TERMINAL_AGENTS = [ description: "Mastra's coding agent for building, debugging, and shipping code from the terminal.", command: "mastracode", + promptCommand: "mastracode --prompt", + promptCommandSuffix: "; mastracode", }), createBuiltinTerminalAgent({ id: "opencode", @@ -131,7 +133,7 @@ export const BUILTIN_TERMINAL_AGENTS = [ description: "GitHub's coding agent for planning, editing, and building in your repo.", command: "copilot --allow-tool=write", - promptCommand: "copilot -i --allow-tool=write", + promptCommand: "copilot --allow-tool=write -i", includeInDefaultTerminalPresets: true, }), createBuiltinTerminalAgent({