fix(composer): reconcile live-activity strip with the dock geometry from #3151

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 <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
Taylor Ho
2026-08-05 16:42:03 -07:00
committed by Carl
parent fb2a99598c
commit 0d98a40a78
2 changed files with 12 additions and 83 deletions
@@ -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<typeof BotActivityComposerAction>["agents"];
channel: ComponentProps<typeof TypingIndicatorRow>["channel"];
currentPubkey: ComponentProps<typeof TypingIndicatorRow>["currentPubkey"];
onOpenAgentSession: ComponentProps<
typeof BotActivityComposerAction
>["onOpenAgentSession"];
openAgentSessionPubkey: ComponentProps<
typeof BotActivityComposerAction
>["openAgentSessionPubkey"];
profiles: ComponentProps<typeof BotActivityComposerAction>["profiles"];
typingPubkeys: string[];
visible: boolean;
workingBotPubkeys: string[];
};
export function ChannelComposerActivityAccessory({
agents,
channel,
currentPubkey,
onOpenAgentSession,
openAgentSessionPubkey,
profiles,
typingPubkeys,
visible,
workingBotPubkeys,
}: ChannelComposerActivityAccessoryProps) {
const cardMintJobs = useCardMintJobs();
return (
<ComposerActivityAccessory
className="px-5"
testId="channel-composer-activity-row"
visible={visible}
>
<div className="flex w-full items-center gap-2 overflow-visible pl-2">
{cardMintJobs.length > 0 ? <CardMintComposerChip /> : null}
{workingBotPubkeys.length > 0 ? (
<div className="flex min-w-0 flex-1 overflow-visible">
<BotActivityComposerAction
agents={agents}
channelId={channel?.id ?? null}
onOpenAgentSession={onOpenAgentSession}
openAgentSessionPubkey={openAgentSessionPubkey}
profiles={profiles}
workingBotPubkeys={workingBotPubkeys}
variant="inline"
/>
</div>
) : null}
{typingPubkeys.length > 0 ? (
<TypingIndicatorRow
channel={channel}
className="min-w-0 flex-1 py-0 pl-[calc(0.75rem+1px)] pr-0 sm:pl-[calc(1rem+1px)]"
currentPubkey={currentPubkey}
profiles={profiles}
typingPubkeys={typingPubkeys}
/>
) : null}
</div>
</ComposerActivityAccessory>
);
}
@@ -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. */}
<ComposerActivityAccessory visible={hasComposerBottomActivity}>
<ChannelComposerActivityRow
agents={activityAgents}
@@ -895,8 +895,7 @@ export const ChannelPane = React.memo(function ChannelPane({
)}
threadReplyUnreadCounts={threadReplyUnreadCounts}
activityAccessoryVisible={
hasThreadComposerBotActivity ||
threadTypingPubkeys.length > 0
hasThreadComposerBotActivity || threadTypingPubkeys.length > 0
}
activityAccessoryContent={
hasThreadComposerBotActivity ||