diff --git a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/EmbeddableChat.tsx b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/EmbeddableChat.tsx index 250d8977..1edc2825 100644 --- a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/EmbeddableChat.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/EmbeddableChat.tsx @@ -1,3 +1,4 @@ +import type { ReactNode } from 'react'; import type { UseChatType } from '../../../hooks/useChat'; import { useEmbeddableChat } from './useEmbeddableChat'; import { MessageList } from '../components/MessageList'; @@ -5,6 +6,14 @@ import { InputArea } from '../components/InputArea'; type EmbeddableChatProps = { sessionId?: string; + /** + * What the transcript shows before there is anything in it. `null` shows nothing. + * + * The default, "Send a message to start", is true on the chat screen and wrong wherever something else + * already explains what to do — a new commander has a setup card and a Start button above it, so the + * message contradicts them and takes 200px of height while doing it. + */ + emptyState?: ReactNode; /** Which panel this is — see `queue-store`. Absent on the screen, where there is only one chat. */ panelId?: string; initialModel?: string | null; diff --git a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts index e95b1617..7e46354a 100644 --- a/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts +++ b/src/workspaces/officerdev/src/apps/Chat/EmbeddableChat/useEmbeddableChat.ts @@ -1,3 +1,4 @@ +import type { ReactNode } from 'react'; import type { KeyboardEvent } from 'react'; import { useState, useRef, useEffect, useCallback } from 'react'; import { useUserVisibleModels } from 'state/useModels'; @@ -51,6 +52,7 @@ type UseEmbeddableChatParams = { contextId?: string; /** This session is a commander, per `GET /chat/sessions/:id`. See the note where it is surfaced. */ isCommander?: boolean; + emptyState?: ReactNode; }; /** @@ -622,6 +624,7 @@ export function useEmbeddableChat(params: UseEmbeddableChatParams, onMessageComp would lose the brand-new composer, which has no session yet. */ isCommander: params.context === 'command-hq' || params.isCommander === true, + emptyState: params.emptyState, /* Claude's transcript id, which is what a commander is keyed on everywhere — the Command HQ row, the record of what it spawned, the delete cascade. `sessionId` above is OFFICER's handle for the same diff --git a/src/workspaces/officerdev/src/apps/Chat/components/MessageList.tsx b/src/workspaces/officerdev/src/apps/Chat/components/MessageList.tsx index edee25af..0f8284b0 100644 --- a/src/workspaces/officerdev/src/apps/Chat/components/MessageList.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/components/MessageList.tsx @@ -107,11 +107,17 @@ export const MessageList = ({ manager }: MessageListProps) => { )}
- {rows.length === 0 && !isGenerating && ( -
- Send a message to start -
- )} + {rows.length === 0 && + !isGenerating && + // `undefined` means nobody said, so keep the default. `null` means "show nothing", which is what + // a screen that already explains itself above the transcript passes. + (manager.emptyState !== undefined ? ( + manager.emptyState + ) : ( +
+ Send a message to start +
+ ))} {rows.length > 0 && (
diff --git a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx index bbf7dadc..4102aa3b 100644 --- a/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx +++ b/src/workspaces/officerdev/src/apps/CommandHQ/CommandHqDetail.tsx @@ -365,6 +365,7 @@ function NewCommander({ !started && !ready ? { reason: !name.trim() ? 'Name it first…' : 'Choose a working directory first…' } : false } className={!started ? 'shrink-0' : 'min-h-0 flex-1'} + {...(!started ? { emptyState: null } : {})} /> setPickerOpen(false)} onSelect={setCwd} />