naming officerdev/chat in layout.ts rendered a second Hosts panel. the shared
registry is not the thing that decides: PluginScreen renders the workspace with
appTypes={{ allowed, fallback: allowed[0] }} where allowed is THIS plugin's own
panel keys, so an unrecognised appType silently becomes the first panel. that
boundary is deliberate — its comment says a persisted layout must not be able
to render another plugin's panel inside this screen — and it is a different
mechanism from seedAppRegistry merging the panels, which is what the last
commit's reasoning confused it with.
so the panel is ours and EmbeddableChat inside it is the platform's. it is
exported from officerdev for exactly this: the whole composer, transcript,
queue and model picker, with no second implementation to fall behind the
first.
it carries a two-sentence promptPrefix, which is per-panel and costs nobody
else's conversation anything. deliberately short: the skill holds the
knowledge and reaches every session for two lines, so anything longer here
would be the skill written twice and this would be the stale copy. all it says
is where the agent is standing, which is the one thing the skill cannot know.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
44 lines
2.0 KiB
TypeScript
44 lines
2.0 KiB
TypeScript
import type { LayoutNode } from 'officerdev';
|
|
|
|
// Hosts wide, certificates beside it, a chat across the bottom.
|
|
//
|
|
// ── The chat panel is ours; the chat inside it is the platform's ──
|
|
//
|
|
// Naming `officerdev/chat` here does NOT work, and the way it fails is quiet: `PluginScreen` renders the
|
|
// workspace with `appTypes={{ allowed, fallback: allowed[0] }}` where `allowed` is this plugin's own panel
|
|
// keys, so an unrecognised appType becomes the FIRST panel — which is how this layout briefly rendered two
|
|
// Hosts panels. The shared registry and the layout allow-list are different things.
|
|
//
|
|
// So `proxy-manager-chat` is our panel and `EmbeddableChat` inside it is the platform's component. No
|
|
// second chat to maintain, and nothing for the allow-list to reject.
|
|
//
|
|
// It gets a third of the height rather than a column, because a conversation reads badly in a narrow
|
|
// column and the two lists do not: they are scannable at any width, and a chat is not.
|
|
//
|
|
// ── What makes the chat useful HERE ──
|
|
//
|
|
// Nothing in this layout. The agent gets the `Proxy Manager` skill the same way it gets every other one —
|
|
// from this plugin's `skills/` directory, offered in every conversation on the machine, costing two lines
|
|
// until something actually needs it. A chat in this panel is an ordinary chat that happens to be sitting
|
|
// underneath the thing it is being asked about.
|
|
export const defaultLayout: LayoutNode = {
|
|
type: 'group',
|
|
id: 'proxy-manager-root',
|
|
direction: 'vertical',
|
|
children: [
|
|
{
|
|
node: {
|
|
type: 'group',
|
|
id: 'proxy-manager-lists',
|
|
direction: 'horizontal',
|
|
children: [
|
|
{ node: { type: 'panel', id: 'proxy-manager-hosts', appType: 'proxy-manager-hosts' }, size: 62 },
|
|
{ node: { type: 'panel', id: 'proxy-manager-certificates', appType: 'proxy-manager-certificates' }, size: 38 },
|
|
],
|
|
},
|
|
size: 66,
|
|
},
|
|
{ node: { type: 'panel', id: 'proxy-manager-chat', appType: 'proxy-manager-chat' }, size: 34 },
|
|
],
|
|
};
|