the same arrangement proxy-manager got, with one difference that turned out to matter: an email chat does not run in the plugin's chats directory, it runs in the ACCOUNT's, beside emails.db. three things. the panel declares its chat context. it declared none, and it did not need to while email was part of the platform — ChatPanelWrapper recognised the screen by `workspace.id === 'email'` and supplied it. a plugin's workspace key is `screens/plugin/email`, so that id became `plugin/email` on extraction day and the branch silently stopped matching. every email chat since has run somewhere with no mailbox anywhere near it. declaring it here is what that branch's own comment asked for, and it carries the mailbox too, which a hardcoded screen id never could — with two accounts the chat follows the picker. the prompt prefix is now chat/CLAUDE.md. 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 file costs nothing per turn and the person it is about can open it. it says more than the prefix did, because it can afford to: answer from the local db and not from gmail, the screen already shows what you would paste back, and a bulk delete over 19k rows is not reversible from here. the panel gets a header, so the conversation picker is scoped to this mailbox's directory rather than absent. panelId is a prop now instead of the hardcoded "email-chat" — two of these could never have held different conversations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
26 lines
1.2 KiB
TypeScript
26 lines
1.2 KiB
TypeScript
import type { AppRegistryMeta } from 'officerdev';
|
|
import { Inbox, Mail, MessageSquare } from 'lucide-react';
|
|
import { EmailList } from './EmailList';
|
|
import { EmailReader } from './EmailReader';
|
|
import { EmailChatPanel, EmailChatPanelHeader } from './EmailChatPanel';
|
|
|
|
// `panels.ts`, not `.tsx` — discovery checks for that exact name and refuses the plugin by name if it is
|
|
// missing, so the JSX lives in EmailChatPanel.tsx and this file stays a declaration.
|
|
//
|
|
// No component re-exports: the shell mounts these by key, and there is no way to export a component from a
|
|
// plugin. `availableOnPanel: false` throughout, because PluginScreen renders the workspace `locked` — these
|
|
// are not swappable, and offering them in a picker would be a lie.
|
|
export const appRegistryMetas: AppRegistryMeta[] = [
|
|
{ key: 'email-list', name: 'Mail', icon: Inbox, component: EmailList, availableOnPanel: false },
|
|
{ key: 'email-reader', name: 'Message', icon: Mail, component: EmailReader, availableOnPanel: false },
|
|
{
|
|
key: 'email-chat',
|
|
name: 'Email chat',
|
|
icon: MessageSquare,
|
|
component: EmailChatPanel,
|
|
// The conversation picker, scoped to this mailbox's own directory.
|
|
header: EmailChatPanelHeader,
|
|
availableOnPanel: false,
|
|
},
|
|
];
|