import { ChatPanelWrapper, ChatHeader } from 'officerdev'; /** * A chat, sitting under the two lists. * * ── Why this exists instead of naming `officerdev/chat` in the layout ── * * It was tried, and it produced two Hosts panels. `PluginScreen` renders the workspace with * `appTypes={{ allowed, fallback: allowed[0] }}` where `allowed` is **this plugin's own panel keys**, so a * layout naming anything else silently falls back to the first one. That is deliberate and its comment * says why: a persisted layout must not be able to render another plugin's panel inside this screen. * * The registry being shared is a separate thing from the layout being allowed to name what is in it. Both * are true; only the second one decides this. * * So the panel is ours and the chat inside it is the platform's. `EmbeddableChat` is exported from * `officerdev` for precisely this — the whole composer, transcript, queue and model picker, with no second * implementation to fall behind the first. * * ── What these chats are told, and where it lives ── * * `chat/CLAUDE.md`, in this plugin. The platform copies it into the chats directory whenever a chat starts * there, and Claude Code reads it from its own cwd at session start. * * There WAS a `promptPrefix` here and it is gone. A prefix rides every message: paid per turn forever, * invisible as a design artefact because it lives in a TypeScript constant, and visible in the one place * it should not be — the owner sent three words and watched a paragraph of preamble go out attached to * them. The file costs nothing per turn and can be opened by the person it is about. */ const CHAT_CONTEXT = { context: 'plugin', contextId: 'proxy-manager' } as const; /** * `ChatPanelWrapper`, not `EmbeddableChat` — one level up, and everything below it comes free. * * The wrapper already carries the session persistence (`usePanelSession`, so this panel stays on its own * conversation across a reload), the agent identity bar, the spawned-by bar, and the resume-the-newest * behaviour. Mounting the composer directly meant reimplementing all of that or going without it, which is * what this panel was doing. */ export const ChatPanel = ({ panelId }: { panelId: string }) => (
); /** * The panel's header: the conversation picker, scoped to this plugin's directory. * * A registry `header` is mounted with `{ panelId }` only, so the context is bound here rather than passed * — which is the whole reason this wrapper exists. */ export const ChatPanelHeader = ({ panelId }: { panelId: string }) => ( );