# chat — `@djangocfg/ui-tools/chat`

Decomposed, transport-agnostic chat UI: bubbles, composer, tool-call panels,
message blocks, link previews. Consumed from npm AND vendored into cmdop
desktop via `pnpm sync:cfg`. See `README.md` for the full API; `@docs/` for
design + troubleshooting.

## Public entry — `lazy.tsx` (the `./chat` subpath)

`package.json` maps `"./chat"` → `src/tools/chat/lazy.tsx`. It does
`export * from './messages'` (+ composer/shell/launcher) and a few **explicit**
re-exports.

**Invariant — explicit-export gotcha.** A newly added **value** export that an
external host imports from `@djangocfg/ui-tools/chat` MUST be listed explicitly
in `lazy.tsx` (like `MarkdownMessage`, `ToolPayloadValue`). `export *` forwards
types but drops a fresh value export at runtime under `'use client'` + Vite →
`does not provide an export named X`. Not a cache bug. See
[`@docs/troubleshooting.md`](./@docs/troubleshooting.md) §1.

## Shared slots — extract, don't fork

A host can fork `MessageBubble` (cmdop does, to inject `@machine` chips). To
stop forks silently losing features, bubble features are **extracted
components** the fork re-renders, not inline code:

- `ToolPayloadValue` — the one payload renderer (object→JsonTree, string→`<pre>`,
  XSS-safe). Used by the default `ToolCalls` panel AND any host card that owns
  the panel via `renderToolCall`. [`@docs/tool-call-rendering.md`](./@docs/tool-call-rendering.md)
- `AutoLinkPreview` — auto-detect URL→preview slot, rendered by `MessageBubble`
  and every fork. [`@docs/link-preview.md`](./@docs/link-preview.md)

**Rule:** adding a shared bubble feature → extract a component + export it (and
list it in `lazy.tsx` if a host imports it directly).

## Producer contract — tool payloads

`ChatToolCall.input`/`.output` are `unknown` so a real object flows through and
renders as a JSON tree. A producer that sends a JSON **string** (or
double-encodes one) gets a flat/escaped `<pre>` — the frontend never
un-escapes (sanitization). Fix on the producer: send a value, encode once.
[`@docs/troubleshooting.md`](./@docs/troubleshooting.md) §2-3.

## Docs

| Doc | Covers |
|---|---|
| [`@docs/tool-call-rendering.md`](./@docs/tool-call-rendering.md) | `ToolCalls` panels, `renderToolCall` vs payload props, `ToolPayloadValue`, JSON-tree contract |
| [`@docs/link-preview.md`](./@docs/link-preview.md) | `AutoLinkPreview` auto-detect, `LinkPreviewCard`, fork-drift fix |
| [`@docs/message-blocks.md`](./@docs/message-blocks.md) | typed `blocks[]` registry (`json`/`link`/`map`/… renderers) |
| [`@docs/troubleshooting.md`](./@docs/troubleshooting.md) | export gotcha, double-encoding, `<pre>`-vs-tree, fork drift, sync:cfg |
