From 0d98a40a78bace656bb408bf4ef43662e1a4ceb3 Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Thu, 30 Jul 2026 16:10:03 -0700 Subject: [PATCH] fix(composer): reconcile live-activity strip with the dock geometry from #3151 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Post-rebase integration fixes after rebasing onto main, which landed the composer dock geometry contract (PR #3151) in the same region this branch reworks. The rebase kept main's dock architecture (reserved bottom rail + ComposerActivityAccessory fade) with the branch's pill strip rendered inside it; this commit cleans up the fallout: - ChannelPane.tsx: re-add the useChannelWorkingAgentPubkeys import — the dock's reserved-rail toggle (composer-dock--with-activity) still needs the channel-level working-set check even though ChannelComposerActivityRow computes its own copy — and consolidate the gating into a single hasComposerBottomActivity expression - ChannelComposerActivityAccessory.tsx: delete — main's channel-level wrapper from #3151 is fully superseded by ChannelComposerActivityRow rendered inside ComposerActivityAccessory - AppShell.tsx / routes/root.tsx: move the temporary DebugHarnessMount from AppShell (999/1000 lines on main, so the mount no longer fits the file-size ratchet) to the root route via a RootComponent wrapper - agents/debug/README.md + DebugHarnessMount.tsx: update the removal instructions and header comment for the new mount location Validated with just desktop-check, 3,817 desktop unit tests, and the channels / composer-overflow / threadpane-ultrawide e2e specs (88 passing). Co-authored-by: Taylor Ho Signed-off-by: Taylor Ho --- .../ui/ChannelComposerActivityAccessory.tsx | 70 ------------------- .../src/features/channels/ui/ChannelPane.tsx | 25 ++++--- 2 files changed, 12 insertions(+), 83 deletions(-) delete mode 100644 desktop/src/features/channels/ui/ChannelComposerActivityAccessory.tsx diff --git a/desktop/src/features/channels/ui/ChannelComposerActivityAccessory.tsx b/desktop/src/features/channels/ui/ChannelComposerActivityAccessory.tsx deleted file mode 100644 index f99888f01..000000000 --- a/desktop/src/features/channels/ui/ChannelComposerActivityAccessory.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import type { ComponentProps } from "react"; - -import { CardMintComposerChip } from "@/features/agents/ui/CardMintComposerChip"; -import { useCardMintJobs } from "@/features/agents/cardMintStore"; -import { BotActivityComposerAction } from "@/features/channels/ui/BotActivityBar"; -import { ComposerActivityAccessory } from "@/features/messages/ui/ComposerActivityAccessory"; -import { TypingIndicatorRow } from "@/features/messages/ui/TypingIndicatorRow"; - -type ChannelComposerActivityAccessoryProps = { - agents: ComponentProps["agents"]; - channel: ComponentProps["channel"]; - currentPubkey: ComponentProps["currentPubkey"]; - onOpenAgentSession: ComponentProps< - typeof BotActivityComposerAction - >["onOpenAgentSession"]; - openAgentSessionPubkey: ComponentProps< - typeof BotActivityComposerAction - >["openAgentSessionPubkey"]; - profiles: ComponentProps["profiles"]; - typingPubkeys: string[]; - visible: boolean; - workingBotPubkeys: string[]; -}; - -export function ChannelComposerActivityAccessory({ - agents, - channel, - currentPubkey, - onOpenAgentSession, - openAgentSessionPubkey, - profiles, - typingPubkeys, - visible, - workingBotPubkeys, -}: ChannelComposerActivityAccessoryProps) { - const cardMintJobs = useCardMintJobs(); - return ( - -
- {cardMintJobs.length > 0 ? : null} - {workingBotPubkeys.length > 0 ? ( -
- -
- ) : null} - {typingPubkeys.length > 0 ? ( - - ) : null} -
-
- ); -} diff --git a/desktop/src/features/channels/ui/ChannelPane.tsx b/desktop/src/features/channels/ui/ChannelPane.tsx index dc17a2b03..fc013722b 100644 --- a/desktop/src/features/channels/ui/ChannelPane.tsx +++ b/desktop/src/features/channels/ui/ChannelPane.tsx @@ -2,6 +2,7 @@ import * as React from "react"; import { Hash, LogIn } from "lucide-react"; import { AnimatePresence } from "motion/react"; import { useAppNavigation } from "@/app/navigation/useAppNavigation"; +import { useChannelWorkingAgentPubkeys } from "@/features/agents/agentWorkingSignal"; import { useMediaUpload } from "@/features/messages/lib/useMediaUpload"; import { ComposerDockBackdrop } from "@/features/messages/ui/ComposerDockBackdrop"; import { ComposerUploadProgressOverlay } from "@/features/messages/ui/ComposerUploadProgressOverlay"; @@ -399,18 +400,18 @@ export const ChannelPane = React.memo(function ChannelPane({ !isComposerDisabled && !isMainDeferredEditPending && !isSinglePanelView; - const hasTypingActivity = typingPubkeys.length > 0; - // Unified working set for the composer bar: observer-derived turns primary, - // bot typing fallback (both folded together by agentWorkingSignal). This is - // what makes the bar show for an agent whose observer stream is live but - // whose typing signal never arrives — and vice versa. + // Working set for the composer bar (observer turns + bot-typing fallback, + // folded by agentWorkingSignal); gates the dock's reserved bottom rail. const composerWorkingBotPubkeys = useChannelWorkingAgentPubkeys( activeChannel?.id ?? null, ); - const hasComposerBotActivity = composerWorkingBotPubkeys.length > 0; + // Background card mints surface in the same rail ("Minting card…" chip), + // so they must also reserve the activity row. const hasCardMintActivity = useCardMintJobs().length > 0; const hasComposerBottomActivity = - hasComposerBotActivity || hasTypingActivity || hasCardMintActivity; + composerWorkingBotPubkeys.length > 0 || + typingPubkeys.length > 0 || + hasCardMintActivity; const threadComposerBotTypingPubkeys = React.useMemo(() => { if (!openThreadHeadId) return []; return botTypingEntries @@ -795,10 +796,9 @@ export const ChannelPane = React.memo(function ChannelPane({ } showTopBorder={false} /> - {/* The activity accessory is anchored in the dock's reserved - bottom rail, so fading it cannot change the observed - overlay height or move the conversation. Its natural - content height remains responsive. */} + {/* The accessory is anchored in the dock's reserved bottom + rail, so fading it cannot change the observed overlay + height or move the conversation. */} 0 + hasThreadComposerBotActivity || threadTypingPubkeys.length > 0 } activityAccessoryContent={ hasThreadComposerBotActivity ||