@hanzo/ui 8.1.5 → 8.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +4 -2
  2. package/dist/backends/gui/textarea.cjs +5 -10
  3. package/dist/backends/gui/textarea.d.ts +11 -32
  4. package/dist/backends/gui/textarea.d.ts.map +1 -1
  5. package/dist/backends/gui/textarea.js +5 -10
  6. package/dist/backends/gui/textarea.js.map +1 -1
  7. package/dist/chat/Composer.cjs +10 -46
  8. package/dist/chat/Composer.d.ts +11 -30
  9. package/dist/chat/Composer.d.ts.map +1 -1
  10. package/dist/chat/Composer.js +10 -46
  11. package/dist/chat/Composer.js.map +1 -1
  12. package/dist/chat/Failure.cjs +9 -28
  13. package/dist/chat/Failure.d.ts +6 -20
  14. package/dist/chat/Failure.d.ts.map +1 -1
  15. package/dist/chat/Failure.js +9 -28
  16. package/dist/chat/Failure.js.map +1 -1
  17. package/dist/chat/Message.cjs +11 -34
  18. package/dist/chat/Message.d.ts +12 -40
  19. package/dist/chat/Message.d.ts.map +1 -1
  20. package/dist/chat/Message.js +11 -34
  21. package/dist/chat/Message.js.map +1 -1
  22. package/dist/chat/Sources.cjs +6 -24
  23. package/dist/chat/Sources.d.ts +8 -28
  24. package/dist/chat/Sources.d.ts.map +1 -1
  25. package/dist/chat/Sources.js +6 -24
  26. package/dist/chat/Sources.js.map +1 -1
  27. package/dist/chat/Step.cjs +16 -42
  28. package/dist/chat/Step.d.ts +5 -17
  29. package/dist/chat/Step.d.ts.map +1 -1
  30. package/dist/chat/Step.js +16 -42
  31. package/dist/chat/Step.js.map +1 -1
  32. package/dist/chat/Thread.cjs +4 -27
  33. package/dist/chat/Thread.d.ts +4 -34
  34. package/dist/chat/Thread.d.ts.map +1 -1
  35. package/dist/chat/Thread.js +4 -27
  36. package/dist/chat/Thread.js.map +1 -1
  37. package/dist/chat/index.cjs +20 -61
  38. package/dist/chat/index.d.ts +20 -61
  39. package/dist/chat/index.d.ts.map +1 -1
  40. package/dist/chat/index.js +20 -61
  41. package/dist/chat/index.js.map +1 -1
  42. package/dist/chat/pure.cjs +9 -28
  43. package/dist/chat/pure.d.ts.map +1 -1
  44. package/dist/chat/pure.js +9 -28
  45. package/dist/chat/pure.js.map +1 -1
  46. package/dist/chat/send.cjs +8 -18
  47. package/dist/chat/send.d.ts +5 -12
  48. package/dist/chat/send.d.ts.map +1 -1
  49. package/dist/chat/send.js +8 -18
  50. package/dist/chat/send.js.map +1 -1
  51. package/dist/chat/stick.cjs +2 -4
  52. package/dist/chat/stick.d.ts +2 -4
  53. package/dist/chat/stick.d.ts.map +1 -1
  54. package/dist/chat/stick.js +2 -4
  55. package/dist/chat/stick.js.map +1 -1
  56. package/dist/gallery.d.ts.map +1 -1
  57. package/dist/gallery.html +2840 -0
  58. package/dist/gallery.js.map +1 -1
  59. package/dist/product/CopyButton.d.ts +2 -8
  60. package/dist/product/CopyButton.d.ts.map +1 -1
  61. package/dist/product/CopyButton.js.map +1 -1
  62. package/dist/product/pure.cjs +3 -5
  63. package/dist/product/pure.d.ts.map +1 -1
  64. package/dist/product/pure.js +3 -5
  65. package/dist/product/pure.js.map +1 -1
  66. package/package.json +1 -1
package/dist/chat/Step.js CHANGED
@@ -4,51 +4,29 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  * Step — something the assistant did on the way to the answer, and how it went.
5
5
  *
6
6
  * A tool call, a retrieval, a plan, a stretch of reasoning, a progress report:
7
- * every one of them is a named region that reports a state and opens to show
8
- * its detail. Two repos had written that arrangement NINE times without ever
9
- * naming it — hanzo/chat once (`ToolCall.tsx` + `ProgressText.tsx`), hanzo.app
10
- * eight (`chat-panel/index.tsx` `ToolDisplay`, `SyntheticErrorDisplay`,
11
- * `ReasoningDisplay`, `PlanDisplay`, `AgentDisplay`, `ProgressDisplay`, the
12
- * inline `project_context` block, and the builder's own `CollapsibleSection` in
13
- * `ask-ai/chat-thread.tsx:330`). Nine chances to order the header differently,
14
- * and they took most of them.
7
+ * each is a named region that reports a state and opens to show its detail.
8
+ * The header, the state mark, the disclosure and the frame are here; what goes
9
+ * inside is `children`.
15
10
  *
16
- * What goes INSIDE stays the surface's: chat renders the input as a code block
17
- * and the result through its own markdown, the app renders
18
- * `JSON.stringify(parameters, null, 2)`. That is `children`. The header, the
19
- * state mark, the disclosure and the frame are the same drawing in all nine and
20
- * they are here.
11
+ * Open/closed is `Collapsible`, so `aria-expanded`, `aria-controls` and the
12
+ * keyboard come from the primitive.
21
13
  *
22
- * The open/closed behaviour is `Collapsible`, not a hand-rolled height
23
- * animation. Both existing implementations rolled their own — chat measures
24
- * `scrollHeight` in a `useLayoutEffect`, keeps a `ResizeObserver` alive and
25
- * transitions an explicit pixel height — and that is the keyboard handling and
26
- * the `aria-expanded`/`aria-controls` pair re-derived by hand each time. The
27
- * primitive already has them.
28
- *
29
- * There is no duration and no elapsed time. Neither implementation shows one,
30
- * and chat's apparent progress is not measured at all: `useProgress.ts:54`
31
- * ticks a `setInterval` by 0.007 every 200ms and caps at 0.95 until the server
32
- * says otherwise. A number that is invented should not be given a place to
33
- * render.
14
+ * No duration: nothing upstream measures one, and a progress ratio ticked by a
15
+ * timer is not a measurement.
34
16
  */
35
17
  import { SizableText, XStack, YStack } from '@hanzo/gui';
36
18
  import { Ban, Check, ChevronDown, TriangleAlert } from '@hanzogui/lucide-icons-2';
37
19
  import { Collapsible, CollapsibleContent, CollapsibleTrigger, Spinner } from '../backends/gui/index.js';
38
20
  import { slot } from '../backends/gui/slot.js';
39
- /** Edge of the state mark, px. One size, so the header never reflows on a state
40
- * change — a step that finishes must not move the text beside it. */
21
+ /** Edge of the state mark, px. One size, so a state change never reflows the
22
+ * header. */
41
23
  const MARK = 13;
42
24
  /**
43
25
  * The mark for each state. `running` is the one that moves.
44
26
  *
45
- * Tinted on the glyph, never on the box: `XStack` is a View and has no `color`,
46
- * so a colour set there type-errors rather than cascading — which is this
47
- * package's "a prop must actually arrive" rule catching a habit borrowed from
48
- * the DOM. Written as four call sites rather than a lookup table because the
49
- * Spinner and the three glyphs do not share a props type: the icons take a
50
- * themed `GetThemeValueForKey<'color'>` and the Spinner takes a plain string,
51
- * and the table that unified them only typechecked by widening both to `any`.
27
+ * Tinted on the glyph: `XStack` is a View and takes no `color`. Four call sites
28
+ * rather than a table because the Spinner and the icons do not share a props
29
+ * type — the icons take a themed colour, the Spinner a plain string.
52
30
  */
53
31
  const mark = (status) => {
54
32
  switch (status) {
@@ -63,17 +41,13 @@ const mark = (status) => {
63
41
  }
64
42
  };
65
43
  export function Step({ name, status = 'done', detail, children, defaultOpen, open, onOpenChange, ...props }) {
66
- // A step with no body is a statement, not a control. Rendering a dead chevron
67
- // and a focusable trigger over nothing is how a keyboard user is sent to a
68
- // stop that does not answer.
44
+ // A step with no body is a statement, not a control: no chevron, no trigger,
45
+ // no keyboard stop that does not answer.
69
46
  const opens = children != null;
70
47
  const header = (_jsxs(XStack, { items: "center", gap: "$2", px: "$3", py: "$2", width: "100%", children: [_jsx(XStack, { width: MARK + 1, items: "center", justify: "center", shrink: 0, children: mark(status) }), _jsx(SizableText, { size: "$1", color: "$color12", numberOfLines: 1, children: name }), detail ? (_jsx(SizableText, { size: "$1", color: "$color10", numberOfLines: 1, shrink: 1, children: detail })) : null, _jsx(XStack, { flex: 1 }), opens ? _jsx(ChevronDown, { size: 13, color: "$color10" }) : null] }));
71
48
  return (_jsxs(Collapsible, { ...slot('step'), "data-status": status, open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, width: "100%", rounded: "$4", borderWidth: 1,
72
- // The failure edge, not a red one. `product/tone.ts` states the rule this
73
- // package works under — "this system has no colour to spend" — and marks
74
- // its `stopped` register with a border rather than a fill. A step that
75
- // errored is set apart the same way, so it still reads as a failure in a
76
- // brand that retunes the whole ramp.
49
+ // An edge, not a red fill — `product/tone.ts` marks `stopped` the same
50
+ // way, so it survives a brand that retunes the ramp.
77
51
  borderColor: status === 'error' ? '$color9' : '$borderColor', bg: "$color2", overflow: "hidden", ...props, children: [opens ? _jsx(CollapsibleTrigger, { width: "100%", children: header }) : header, opens ? (_jsx(CollapsibleContent, { children: _jsx(YStack, { ...slot('step-body'), px: "$3", py: "$2.5", gap: "$2", borderTopWidth: 1, borderColor: "$borderColor", children: children }) })) : null] }));
78
52
  }
79
53
  //# sourceMappingURL=Step.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Step.js","sourceRoot":"","sources":["../../src/chat/Step.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Step.js","sourceRoot":"","sources":["../../src/chat/Step.tsx"],"names":[],"mappings":"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"}
@@ -6,32 +6,9 @@ const jsx_runtime_1 = require("react/jsx-runtime");
6
6
  /**
7
7
  * Thread — the scrolling column of turns.
8
8
  *
9
- * It does the one thing every surface had re-solved: follow a streaming answer
10
- * to the bottom, and stop following the instant the reader scrolls up. The
11
- * decision is `pinned()`, asserted without a DOM; this component only wires it
12
- * to the platform's scroll view, so momentum and keyboard stay the host's.
13
- *
14
- * That decision is now the fleet's only answer to "am I at the bottom", which
15
- * had five: 50px in two places, 97%-of-height in a third, an
16
- * `IntersectionObserver` at a 0.85 ratio in a fourth, and on the thread itself
17
- * nothing at all — hanzo.app `/chat` ran `scrollIntoView({behavior:'smooth'})`
18
- * on every `messages` change, and since a streaming turn rewrites `messages`
19
- * per SSE delta, scrolling up to re-read was undone several times a second.
20
- *
21
- * Measured in Chromium against the packed tarball, 2500 tokens at 4ms:
22
- * following holds a 0px gap through 2501 commits; parked at offset 0 the reader
23
- * STAYS at 0 while content grows 1015 → 1375; returning to the end resumes
24
- * following at 0px.
25
- *
26
- * There is no `onLayout` here any more, and nothing is lost with it. It was
27
- * passed to keep a `track` ref current, gui does not implement it on this
28
- * component so React forwarded it to the DOM as an unknown handler — the noise
29
- * hanzo.app reported — and the ref it fed was WRITE-ONLY: `track` was read in
30
- * exactly one place, `onScroll`, which rebuilds all three numbers from the
31
- * event before reading them. So the handler was dead, the state it kept was
32
- * dead, and the measurement the two together looked like they were doing was
33
- * being done properly a few lines below the whole time. The scroll event
34
- * carries `layoutMeasurement`; nothing else needs to ask.
9
+ * Follows a streaming answer to the bottom and stops the moment the reader
10
+ * scrolls up. The decision is `pinned()`; this only wires it to the platform's
11
+ * scroll view, so momentum and keyboard stay the host's.
35
12
  */
36
13
  const gui_1 = require("@hanzo/gui");
37
14
  const react_1 = require("react");
@@ -42,7 +19,7 @@ const MEASURE = 768;
42
19
  exports.Thread = (0, react_1.forwardRef)(function Thread({ children, maxWidth = MEASURE, slack = stick_1.SLACK, gap = 24, onScroll, column, ...props }, ref) {
43
20
  const view = (0, react_1.useRef)(null);
44
21
  const follow = (0, react_1.useRef)(true);
45
- // Ours to scroll with, the caller's because three consumers need this node.
22
+ // Ours to scroll with, and the caller's.
46
23
  const hold = (0, react_1.useCallback)((el) => {
47
24
  view.current = el;
48
25
  if (typeof ref === 'function')
@@ -1,32 +1,9 @@
1
1
  /**
2
2
  * Thread — the scrolling column of turns.
3
3
  *
4
- * It does the one thing every surface had re-solved: follow a streaming answer
5
- * to the bottom, and stop following the instant the reader scrolls up. The
6
- * decision is `pinned()`, asserted without a DOM; this component only wires it
7
- * to the platform's scroll view, so momentum and keyboard stay the host's.
8
- *
9
- * That decision is now the fleet's only answer to "am I at the bottom", which
10
- * had five: 50px in two places, 97%-of-height in a third, an
11
- * `IntersectionObserver` at a 0.85 ratio in a fourth, and on the thread itself
12
- * nothing at all — hanzo.app `/chat` ran `scrollIntoView({behavior:'smooth'})`
13
- * on every `messages` change, and since a streaming turn rewrites `messages`
14
- * per SSE delta, scrolling up to re-read was undone several times a second.
15
- *
16
- * Measured in Chromium against the packed tarball, 2500 tokens at 4ms:
17
- * following holds a 0px gap through 2501 commits; parked at offset 0 the reader
18
- * STAYS at 0 while content grows 1015 → 1375; returning to the end resumes
19
- * following at 0px.
20
- *
21
- * There is no `onLayout` here any more, and nothing is lost with it. It was
22
- * passed to keep a `track` ref current, gui does not implement it on this
23
- * component so React forwarded it to the DOM as an unknown handler — the noise
24
- * hanzo.app reported — and the ref it fed was WRITE-ONLY: `track` was read in
25
- * exactly one place, `onScroll`, which rebuilds all three numbers from the
26
- * event before reading them. So the handler was dead, the state it kept was
27
- * dead, and the measurement the two together looked like they were doing was
28
- * being done properly a few lines below the whole time. The scroll event
29
- * carries `layoutMeasurement`; nothing else needs to ask.
4
+ * Follows a streaming answer to the bottom and stops the moment the reader
5
+ * scrolls up. The decision is `pinned()`; this only wires it to the platform's
6
+ * scroll view, so momentum and keyboard stay the host's.
30
7
  */
31
8
  import { ScrollView, YStack, type GetRef } from '@hanzo/gui';
32
9
  import { type ComponentProps, type ReactNode } from 'react';
@@ -43,14 +20,7 @@ export interface ThreadProps extends Omit<ComponentProps<typeof ScrollView>, 'ch
43
20
  /** How near the end still counts as "at the bottom", in px. */
44
21
  slack?: number;
45
22
  gap?: number;
46
- /**
47
- * The scroll, after the follow decision is made — with `at`, the answer.
48
- *
49
- * Three separate consumers need this element and this fact: the follow
50
- * decision, a scroll-to-bottom button, and a surface's own turn-offset
51
- * bookkeeping. Deciding privately and publishing nothing is what left each of
52
- * them measuring the scroller again, differently.
53
- */
23
+ /** The scroll, with the follow decision and the numbers it was made from. */
54
24
  onScroll?: (event: unknown, at: {
55
25
  pinned: boolean;
56
26
  track: Track;
@@ -1 +1 @@
1
- {"version":3,"file":"Thread.d.ts","sourceRoot":"","sources":["../../src/chat/Thread.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAmC,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAG5F,OAAO,EAAiB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAKnD,KAAK,QAAQ,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,GAAG;IAAE,WAAW,CAAC,CAAC,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;CAAE,CAAA;AAE3F,MAAM,WAAW,WACf,SAAQ,IAAI,CAAC,cAAc,CAAC,OAAO,UAAU,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACxE,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,KAAK,IAAI,CAAA;IAC1E,6EAA6E;IAC7E,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;CACzD;AAED,eAAO,MAAM,MAAM,+GAqDjB,CAAA"}
1
+ {"version":3,"file":"Thread.d.ts","sourceRoot":"","sources":["../../src/chat/Thread.tsx"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAmC,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAG5F,OAAO,EAAiB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAKnD,KAAK,QAAQ,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,GAAG;IAAE,WAAW,CAAC,CAAC,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAA;CAAE,CAAA;AAE3F,MAAM,WAAW,WACf,SAAQ,IAAI,CAAC,cAAc,CAAC,OAAO,UAAU,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;IACxE,QAAQ,CAAC,EAAE,SAAS,CAAA;IACpB,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,KAAK,IAAI,CAAA;IAC1E,6EAA6E;IAC7E,MAAM,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,EAAE,UAAU,CAAC,CAAA;CACzD;AAED,eAAO,MAAM,MAAM,+GAqDjB,CAAA"}
@@ -3,32 +3,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  /**
4
4
  * Thread — the scrolling column of turns.
5
5
  *
6
- * It does the one thing every surface had re-solved: follow a streaming answer
7
- * to the bottom, and stop following the instant the reader scrolls up. The
8
- * decision is `pinned()`, asserted without a DOM; this component only wires it
9
- * to the platform's scroll view, so momentum and keyboard stay the host's.
10
- *
11
- * That decision is now the fleet's only answer to "am I at the bottom", which
12
- * had five: 50px in two places, 97%-of-height in a third, an
13
- * `IntersectionObserver` at a 0.85 ratio in a fourth, and on the thread itself
14
- * nothing at all — hanzo.app `/chat` ran `scrollIntoView({behavior:'smooth'})`
15
- * on every `messages` change, and since a streaming turn rewrites `messages`
16
- * per SSE delta, scrolling up to re-read was undone several times a second.
17
- *
18
- * Measured in Chromium against the packed tarball, 2500 tokens at 4ms:
19
- * following holds a 0px gap through 2501 commits; parked at offset 0 the reader
20
- * STAYS at 0 while content grows 1015 → 1375; returning to the end resumes
21
- * following at 0px.
22
- *
23
- * There is no `onLayout` here any more, and nothing is lost with it. It was
24
- * passed to keep a `track` ref current, gui does not implement it on this
25
- * component so React forwarded it to the DOM as an unknown handler — the noise
26
- * hanzo.app reported — and the ref it fed was WRITE-ONLY: `track` was read in
27
- * exactly one place, `onScroll`, which rebuilds all three numbers from the
28
- * event before reading them. So the handler was dead, the state it kept was
29
- * dead, and the measurement the two together looked like they were doing was
30
- * being done properly a few lines below the whole time. The scroll event
31
- * carries `layoutMeasurement`; nothing else needs to ask.
6
+ * Follows a streaming answer to the bottom and stops the moment the reader
7
+ * scrolls up. The decision is `pinned()`; this only wires it to the platform's
8
+ * scroll view, so momentum and keyboard stay the host's.
32
9
  */
33
10
  import { ScrollView, YStack } from '@hanzo/gui';
34
11
  import { forwardRef, useCallback, useRef } from 'react';
@@ -39,7 +16,7 @@ const MEASURE = 768;
39
16
  export const Thread = /* @__PURE__ */ forwardRef(function Thread({ children, maxWidth = MEASURE, slack = SLACK, gap = 24, onScroll, column, ...props }, ref) {
40
17
  const view = useRef(null);
41
18
  const follow = useRef(true);
42
- // Ours to scroll with, the caller's because three consumers need this node.
19
+ // Ours to scroll with, and the caller's.
43
20
  const hold = useCallback((el) => {
44
21
  view.current = el;
45
22
  if (typeof ref === 'function')
@@ -1 +1 @@
1
- {"version":3,"file":"Thread.js","sourceRoot":"","sources":["../../src/chat/Thread.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAe,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAuC,MAAM,OAAO,CAAA;AAE5F,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,KAAK,EAAc,MAAM,SAAS,CAAA;AAEnD,4CAA4C;AAC5C,MAAM,OAAO,GAAG,GAAG,CAAA;AAyBnB,MAAM,CAAC,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAwB,SAAS,MAAM,CACrF,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,GAAG,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EACrF,GAAG;IAEH,MAAM,IAAI,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IAE3B,4EAA4E;IAC5E,MAAM,IAAI,GAAG,WAAW,CACtB,CAAC,EAAmB,EAAE,EAAE;QACtB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,IAAI,OAAO,GAAG,KAAK,UAAU;YAAE,GAAG,CAAC,EAAE,CAAC,CAAA;aACjC,IAAI,GAAG;YAAG,GAA+C,CAAC,OAAO,GAAG,EAAE,CAAA;IAC7E,CAAC,EACD,CAAC,GAAG,CAAC,CACN,CAAA;IAED,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,IAAI,MAAM,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IACpE,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,KAAC,UAAU,IACT,GAAG,EAAE,IAAa,KACd,IAAI,CAAC,QAAQ,CAAC,EAClB,IAAI,EAAE,CAAC,EACP,KAAK,EAAC,MAAM,EACZ,mBAAmB,EAAE,EAAE,EACvB,mBAAmB,EAAE,IAAI,EACzB,QAAQ,EAAE,CAAC,CAAM,EAAE,EAAE;YACnB,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,WAAW,CAAA;YACvE,MAAM,KAAK,GAAU;gBACnB,MAAM,EAAE,aAAa,CAAC,CAAC;gBACvB,QAAQ,EAAE,iBAAiB,CAAC,MAAM;gBAClC,OAAO,EAAE,WAAW,CAAC,MAAM;aAC5B,CAAA;YACD,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YACrC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;QAClD,CAAC,KACG,KAAK,YAET,KAAC,MAAM,OACD,IAAI,CAAC,eAAe,CAAC,EACzB,KAAK,EAAC,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,GAAG,KACH,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAiB,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KACzE,MAAM,YAET,QAAQ,GACF,GACE,CACd,CAAA;AACH,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"Thread.js","sourceRoot":"","sources":["../../src/chat/Thread.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAe,MAAM,YAAY,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAuC,MAAM,OAAO,CAAA;AAE5F,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,KAAK,EAAc,MAAM,SAAS,CAAA;AAEnD,4CAA4C;AAC5C,MAAM,OAAO,GAAG,GAAG,CAAA;AAkBnB,MAAM,CAAC,MAAM,MAAM,GAAG,eAAe,CAAC,UAAU,CAAwB,SAAS,MAAM,CACrF,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,GAAG,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EACrF,GAAG;IAEH,MAAM,IAAI,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IAE3B,yCAAyC;IACzC,MAAM,IAAI,GAAG,WAAW,CACtB,CAAC,EAAmB,EAAE,EAAE;QACtB,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;QACjB,IAAI,OAAO,GAAG,KAAK,UAAU;YAAE,GAAG,CAAC,EAAE,CAAC,CAAA;aACjC,IAAI,GAAG;YAAG,GAA+C,CAAC,OAAO,GAAG,EAAE,CAAA;IAC7E,CAAC,EACD,CAAC,GAAG,CAAC,CACN,CAAA;IAED,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,IAAI,MAAM,CAAC,OAAO;YAAE,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IACpE,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,KAAC,UAAU,IACT,GAAG,EAAE,IAAa,KACd,IAAI,CAAC,QAAQ,CAAC,EAClB,IAAI,EAAE,CAAC,EACP,KAAK,EAAC,MAAM,EACZ,mBAAmB,EAAE,EAAE,EACvB,mBAAmB,EAAE,IAAI,EACzB,QAAQ,EAAE,CAAC,CAAM,EAAE,EAAE;YACnB,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,WAAW,CAAA;YACvE,MAAM,KAAK,GAAU;gBACnB,MAAM,EAAE,aAAa,CAAC,CAAC;gBACvB,QAAQ,EAAE,iBAAiB,CAAC,MAAM;gBAClC,OAAO,EAAE,WAAW,CAAC,MAAM;aAC5B,CAAA;YACD,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YACrC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;QAClD,CAAC,KACG,KAAK,YAET,KAAC,MAAM,OACD,IAAI,CAAC,eAAe,CAAC,EACzB,KAAK,EAAC,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,GAAG,KACH,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAiB,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KACzE,MAAM,YAET,QAAQ,GACF,GACE,CACd,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -4,73 +4,32 @@ exports.SourceCard = exports.Sources = exports.Failure = exports.Step = exports.
4
4
  /**
5
5
  * @hanzo/ui/chat — the one chat shell, on @hanzo/gui primitives.
6
6
  *
7
- * Shell only: Thread scrolls, Message presents a turn, Composer takes a draft,
8
- * Sidebar navigates between conversations, Header names the current one, and
9
- * Code, Step, Failure and Sources present the pieces of a turn every surface
10
- * renders the same way.
7
+ * Thread scrolls, Message presents a turn, Composer takes a draft, Sidebar
8
+ * navigates between conversations, Header names the current one, and Code,
9
+ * Step, Failure and Sources present the pieces of a turn.
11
10
  *
12
- * This file used to end that sentence with "Content rendering (markdown, tool
13
- * calls) stays with the surface — they disagree on the pipeline, and none of it
14
- * is presentational." Half of that was right and the half that was wrong cost
15
- * nine hand-drawn copies. Re-decided by reading what the three surfaces
16
- * actually render:
11
+ * The markdown pipeline is the surface's and arrives as `children`: the three
12
+ * surfaces run nine plugins, one plugin, and a regex under a bundle ceiling
13
+ * that cannot afford a parser. There is no `renderPart` prop for the same
14
+ * reason — the part union is per-surface too, so a callback here would take a
15
+ * Part type matching nobody's.
17
16
  *
18
- * MARKDOWN STAYS OUT, and not as a preference. hanzo/chat runs seven remark
19
- * plugins and two rehype plugins (`Content/Markdown.tsx:42-65`, including
20
- * katex and highlight.js over a 35-language subset); hanzo.app runs
21
- * remark-gfm and nothing else (`markdown-renderer/index.tsx:107`); the
22
- * extension parses markdown with eighty lines of regex and no dependency at
23
- * all (`answer/markdown.ts`) because `newtab.js` measures 485.9 KB against a
24
- * 500 KB ceiling that fails the build (`scripts/check-bundle-budgets.mjs:29`)
25
- * and its MV3 policy is `script-src 'self'`. Fourteen kilobytes of headroom
26
- * is not a pipeline disagreement to be reconciled; it is a surface that
27
- * cannot afford a parser. So the pipeline is the surface's, and `children` is
28
- * how it arrives — which is also why there is no `renderPart` prop: the part
29
- * UNION is per-surface too (twelve item types in the app's
30
- * `chat-panel/index.tsx` `TurnDisplay`, eight in chat's `Content/Part.tsx`,
31
- * none in the extension), so a callback here would need a Part type that
32
- * matches nobody's. The surface maps its own parts and passes nodes.
17
+ * Everything else about a turn is presentational and lives here: the code
18
+ * frame, the step disclosure, the failure, the streaming caret.
33
19
  *
34
- * THE REST OF IT WAS ALWAYS PRESENTATIONAL. A code block with a language
35
- * label and a copy control, a collapsible step with a state mark, a failure
36
- * with a retry, a streaming caret — every surface draws these and no two draw
37
- * them alike. `Step` alone replaces nine copies across two repos. What is
38
- * inside each of them is still `children`; the frame, the header, the mark
39
- * and the disclosure are here.
20
+ * Props-in, callbacks-out — no transport, no store, no routing. Each component
21
+ * spreads its residual props, and the three that own an inner part publish a
22
+ * way through to it (`Message body`, `Thread column`, `Composer field`).
40
23
  *
41
- * Everything is props-in, callbacks-out: no transport, no store, no routing, no
42
- * active-id resolution. The same components serve a live conversation, a shared
43
- * read-only transcript and a test fixture.
24
+ * `@hanzo/ui/chat/pure` carries `sends`, `ready`, `pinned` and `SLACK` with no
25
+ * imports, for Node and for callers that are not chat.
44
26
  *
45
- * Every component here spreads its residual props onto its own element, and
46
- * `Message`, `Thread` and `Composer` publish a way through to the part they own
47
- * (`body`, `column`, `field`). They did not, and that closed list was the ONE
48
- * thing keeping hanzo/chat from adopting `Message`: its scroll machinery
49
- * addresses turns by `id`, `SelectionAsk` finds one with
50
- * `closest('.message-render')`, and its turn wears a fleet-wide `glass`
51
- * material against a `bg` welded to `$color3`. None of it exotic, all of it
52
- * free with a spread — gui forwards what it does not recognise, which is the
53
- * mechanism `slot()` is already built on.
27
+ * Styling is `$` tokens throughout, never literal colours, so a brand retunes
28
+ * through its own theme and nothing here carries a mark.
54
29
  *
55
- * `@hanzo/ui/chat/pure` is the same module's decisions with nothing attached:
56
- * `sends`, `ready`, `pinned`, `SLACK`. It exists because `import('@hanzo/ui/chat')`
57
- * cannot load in Node, so no script and no spec could reach them. They are also
58
- * re-exported from `@hanzo/ui/product/pure`, because they are not chat rules —
59
- * ten of the fifteen files importing `sends` in hanzo.app are a SQL editor, a
60
- * file explorer, a command palette, a rename field.
61
- *
62
- * Styling is `$` tokens throughout, never literal colours, so each brand retunes
63
- * through its own theme and nothing here carries a Hanzo mark — which is what
64
- * lets the same shell ship on Lux and Zoo surfaces without leaking a brand.
65
- *
66
- * The model picker is not here: it already ships at `@hanzo/ui/models`, and it
67
- * is not chat-specific.
68
- *
69
- * `CopyButton` is not here either, for the same reason and after the same
70
- * mistake: it lived in `Code.tsx`, so the only way to reach it was
71
- * `@hanzo/ui/chat`, and no one hunting for a copy button looks in a chat module.
72
- * Six surfaces wrote their own instead. It now ships at `@hanzo/ui/product`;
73
- * `Code` imports it from there.
30
+ * The model picker and `CopyButton` are not here — neither is chat-specific, so
31
+ * they ship at `@hanzo/ui/models` and `@hanzo/ui/product`. Nobody hunting for a
32
+ * copy button looks in a chat module.
74
33
  */
75
34
  var Composer_1 = require("./Composer.cjs");
76
35
  Object.defineProperty(exports, "Composer", { enumerable: true, get: function () { return Composer_1.Composer; } });
@@ -1,73 +1,32 @@
1
1
  /**
2
2
  * @hanzo/ui/chat — the one chat shell, on @hanzo/gui primitives.
3
3
  *
4
- * Shell only: Thread scrolls, Message presents a turn, Composer takes a draft,
5
- * Sidebar navigates between conversations, Header names the current one, and
6
- * Code, Step, Failure and Sources present the pieces of a turn every surface
7
- * renders the same way.
4
+ * Thread scrolls, Message presents a turn, Composer takes a draft, Sidebar
5
+ * navigates between conversations, Header names the current one, and Code,
6
+ * Step, Failure and Sources present the pieces of a turn.
8
7
  *
9
- * This file used to end that sentence with "Content rendering (markdown, tool
10
- * calls) stays with the surface — they disagree on the pipeline, and none of it
11
- * is presentational." Half of that was right and the half that was wrong cost
12
- * nine hand-drawn copies. Re-decided by reading what the three surfaces
13
- * actually render:
8
+ * The markdown pipeline is the surface's and arrives as `children`: the three
9
+ * surfaces run nine plugins, one plugin, and a regex under a bundle ceiling
10
+ * that cannot afford a parser. There is no `renderPart` prop for the same
11
+ * reason — the part union is per-surface too, so a callback here would take a
12
+ * Part type matching nobody's.
14
13
  *
15
- * MARKDOWN STAYS OUT, and not as a preference. hanzo/chat runs seven remark
16
- * plugins and two rehype plugins (`Content/Markdown.tsx:42-65`, including
17
- * katex and highlight.js over a 35-language subset); hanzo.app runs
18
- * remark-gfm and nothing else (`markdown-renderer/index.tsx:107`); the
19
- * extension parses markdown with eighty lines of regex and no dependency at
20
- * all (`answer/markdown.ts`) because `newtab.js` measures 485.9 KB against a
21
- * 500 KB ceiling that fails the build (`scripts/check-bundle-budgets.mjs:29`)
22
- * and its MV3 policy is `script-src 'self'`. Fourteen kilobytes of headroom
23
- * is not a pipeline disagreement to be reconciled; it is a surface that
24
- * cannot afford a parser. So the pipeline is the surface's, and `children` is
25
- * how it arrives — which is also why there is no `renderPart` prop: the part
26
- * UNION is per-surface too (twelve item types in the app's
27
- * `chat-panel/index.tsx` `TurnDisplay`, eight in chat's `Content/Part.tsx`,
28
- * none in the extension), so a callback here would need a Part type that
29
- * matches nobody's. The surface maps its own parts and passes nodes.
14
+ * Everything else about a turn is presentational and lives here: the code
15
+ * frame, the step disclosure, the failure, the streaming caret.
30
16
  *
31
- * THE REST OF IT WAS ALWAYS PRESENTATIONAL. A code block with a language
32
- * label and a copy control, a collapsible step with a state mark, a failure
33
- * with a retry, a streaming caret — every surface draws these and no two draw
34
- * them alike. `Step` alone replaces nine copies across two repos. What is
35
- * inside each of them is still `children`; the frame, the header, the mark
36
- * and the disclosure are here.
17
+ * Props-in, callbacks-out — no transport, no store, no routing. Each component
18
+ * spreads its residual props, and the three that own an inner part publish a
19
+ * way through to it (`Message body`, `Thread column`, `Composer field`).
37
20
  *
38
- * Everything is props-in, callbacks-out: no transport, no store, no routing, no
39
- * active-id resolution. The same components serve a live conversation, a shared
40
- * read-only transcript and a test fixture.
21
+ * `@hanzo/ui/chat/pure` carries `sends`, `ready`, `pinned` and `SLACK` with no
22
+ * imports, for Node and for callers that are not chat.
41
23
  *
42
- * Every component here spreads its residual props onto its own element, and
43
- * `Message`, `Thread` and `Composer` publish a way through to the part they own
44
- * (`body`, `column`, `field`). They did not, and that closed list was the ONE
45
- * thing keeping hanzo/chat from adopting `Message`: its scroll machinery
46
- * addresses turns by `id`, `SelectionAsk` finds one with
47
- * `closest('.message-render')`, and its turn wears a fleet-wide `glass`
48
- * material against a `bg` welded to `$color3`. None of it exotic, all of it
49
- * free with a spread — gui forwards what it does not recognise, which is the
50
- * mechanism `slot()` is already built on.
24
+ * Styling is `$` tokens throughout, never literal colours, so a brand retunes
25
+ * through its own theme and nothing here carries a mark.
51
26
  *
52
- * `@hanzo/ui/chat/pure` is the same module's decisions with nothing attached:
53
- * `sends`, `ready`, `pinned`, `SLACK`. It exists because `import('@hanzo/ui/chat')`
54
- * cannot load in Node, so no script and no spec could reach them. They are also
55
- * re-exported from `@hanzo/ui/product/pure`, because they are not chat rules —
56
- * ten of the fifteen files importing `sends` in hanzo.app are a SQL editor, a
57
- * file explorer, a command palette, a rename field.
58
- *
59
- * Styling is `$` tokens throughout, never literal colours, so each brand retunes
60
- * through its own theme and nothing here carries a Hanzo mark — which is what
61
- * lets the same shell ship on Lux and Zoo surfaces without leaking a brand.
62
- *
63
- * The model picker is not here: it already ships at `@hanzo/ui/models`, and it
64
- * is not chat-specific.
65
- *
66
- * `CopyButton` is not here either, for the same reason and after the same
67
- * mistake: it lived in `Code.tsx`, so the only way to reach it was
68
- * `@hanzo/ui/chat`, and no one hunting for a copy button looks in a chat module.
69
- * Six surfaces wrote their own instead. It now ships at `@hanzo/ui/product`;
70
- * `Code` imports it from there.
27
+ * The model picker and `CopyButton` are not here — neither is chat-specific, so
28
+ * they ship at `@hanzo/ui/models` and `@hanzo/ui/product`. Nobody hunting for a
29
+ * copy button looks in a chat module.
71
30
  */
72
31
  export { Composer, ASK, type ComposerProps } from './Composer.js';
73
32
  export { Caret, Message, type MessageProps, type Role } from './Message.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/chat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAA;AACxE,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,QAAQ,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAEnD,OAAO,EACL,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,WAAW,EACX,WAAW,EACX,KAAK,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,QAAQ,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAA;AAEtD,OAAO,EACL,OAAO,EACP,UAAU,EACV,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/chat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAA;AACxE,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,QAAQ,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAEnD,OAAO,EACL,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,WAAW,EACX,WAAW,EACX,KAAK,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,QAAQ,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAA;AAEtD,OAAO,EACL,OAAO,EACP,UAAU,EACV,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,eAAe,GACrB,MAAM,WAAW,CAAA"}
@@ -1,73 +1,32 @@
1
1
  /**
2
2
  * @hanzo/ui/chat — the one chat shell, on @hanzo/gui primitives.
3
3
  *
4
- * Shell only: Thread scrolls, Message presents a turn, Composer takes a draft,
5
- * Sidebar navigates between conversations, Header names the current one, and
6
- * Code, Step, Failure and Sources present the pieces of a turn every surface
7
- * renders the same way.
4
+ * Thread scrolls, Message presents a turn, Composer takes a draft, Sidebar
5
+ * navigates between conversations, Header names the current one, and Code,
6
+ * Step, Failure and Sources present the pieces of a turn.
8
7
  *
9
- * This file used to end that sentence with "Content rendering (markdown, tool
10
- * calls) stays with the surface — they disagree on the pipeline, and none of it
11
- * is presentational." Half of that was right and the half that was wrong cost
12
- * nine hand-drawn copies. Re-decided by reading what the three surfaces
13
- * actually render:
8
+ * The markdown pipeline is the surface's and arrives as `children`: the three
9
+ * surfaces run nine plugins, one plugin, and a regex under a bundle ceiling
10
+ * that cannot afford a parser. There is no `renderPart` prop for the same
11
+ * reason — the part union is per-surface too, so a callback here would take a
12
+ * Part type matching nobody's.
14
13
  *
15
- * MARKDOWN STAYS OUT, and not as a preference. hanzo/chat runs seven remark
16
- * plugins and two rehype plugins (`Content/Markdown.tsx:42-65`, including
17
- * katex and highlight.js over a 35-language subset); hanzo.app runs
18
- * remark-gfm and nothing else (`markdown-renderer/index.tsx:107`); the
19
- * extension parses markdown with eighty lines of regex and no dependency at
20
- * all (`answer/markdown.ts`) because `newtab.js` measures 485.9 KB against a
21
- * 500 KB ceiling that fails the build (`scripts/check-bundle-budgets.mjs:29`)
22
- * and its MV3 policy is `script-src 'self'`. Fourteen kilobytes of headroom
23
- * is not a pipeline disagreement to be reconciled; it is a surface that
24
- * cannot afford a parser. So the pipeline is the surface's, and `children` is
25
- * how it arrives — which is also why there is no `renderPart` prop: the part
26
- * UNION is per-surface too (twelve item types in the app's
27
- * `chat-panel/index.tsx` `TurnDisplay`, eight in chat's `Content/Part.tsx`,
28
- * none in the extension), so a callback here would need a Part type that
29
- * matches nobody's. The surface maps its own parts and passes nodes.
14
+ * Everything else about a turn is presentational and lives here: the code
15
+ * frame, the step disclosure, the failure, the streaming caret.
30
16
  *
31
- * THE REST OF IT WAS ALWAYS PRESENTATIONAL. A code block with a language
32
- * label and a copy control, a collapsible step with a state mark, a failure
33
- * with a retry, a streaming caret — every surface draws these and no two draw
34
- * them alike. `Step` alone replaces nine copies across two repos. What is
35
- * inside each of them is still `children`; the frame, the header, the mark
36
- * and the disclosure are here.
17
+ * Props-in, callbacks-out — no transport, no store, no routing. Each component
18
+ * spreads its residual props, and the three that own an inner part publish a
19
+ * way through to it (`Message body`, `Thread column`, `Composer field`).
37
20
  *
38
- * Everything is props-in, callbacks-out: no transport, no store, no routing, no
39
- * active-id resolution. The same components serve a live conversation, a shared
40
- * read-only transcript and a test fixture.
21
+ * `@hanzo/ui/chat/pure` carries `sends`, `ready`, `pinned` and `SLACK` with no
22
+ * imports, for Node and for callers that are not chat.
41
23
  *
42
- * Every component here spreads its residual props onto its own element, and
43
- * `Message`, `Thread` and `Composer` publish a way through to the part they own
44
- * (`body`, `column`, `field`). They did not, and that closed list was the ONE
45
- * thing keeping hanzo/chat from adopting `Message`: its scroll machinery
46
- * addresses turns by `id`, `SelectionAsk` finds one with
47
- * `closest('.message-render')`, and its turn wears a fleet-wide `glass`
48
- * material against a `bg` welded to `$color3`. None of it exotic, all of it
49
- * free with a spread — gui forwards what it does not recognise, which is the
50
- * mechanism `slot()` is already built on.
24
+ * Styling is `$` tokens throughout, never literal colours, so a brand retunes
25
+ * through its own theme and nothing here carries a mark.
51
26
  *
52
- * `@hanzo/ui/chat/pure` is the same module's decisions with nothing attached:
53
- * `sends`, `ready`, `pinned`, `SLACK`. It exists because `import('@hanzo/ui/chat')`
54
- * cannot load in Node, so no script and no spec could reach them. They are also
55
- * re-exported from `@hanzo/ui/product/pure`, because they are not chat rules —
56
- * ten of the fifteen files importing `sends` in hanzo.app are a SQL editor, a
57
- * file explorer, a command palette, a rename field.
58
- *
59
- * Styling is `$` tokens throughout, never literal colours, so each brand retunes
60
- * through its own theme and nothing here carries a Hanzo mark — which is what
61
- * lets the same shell ship on Lux and Zoo surfaces without leaking a brand.
62
- *
63
- * The model picker is not here: it already ships at `@hanzo/ui/models`, and it
64
- * is not chat-specific.
65
- *
66
- * `CopyButton` is not here either, for the same reason and after the same
67
- * mistake: it lived in `Code.tsx`, so the only way to reach it was
68
- * `@hanzo/ui/chat`, and no one hunting for a copy button looks in a chat module.
69
- * Six surfaces wrote their own instead. It now ships at `@hanzo/ui/product`;
70
- * `Code` imports it from there.
27
+ * The model picker and `CopyButton` are not here — neither is chat-specific, so
28
+ * they ship at `@hanzo/ui/models` and `@hanzo/ui/product`. Nobody hunting for a
29
+ * copy button looks in a chat module.
71
30
  */
72
31
  export { Composer, ASK } from './Composer.js';
73
32
  export { Caret, Message } from './Message.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/chat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AACH,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAsB,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAgC,MAAM,WAAW,CAAA;AACxE,OAAO,EAAE,MAAM,EAAoB,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAa,MAAM,QAAQ,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAc,MAAM,SAAS,CAAA;AAEnD,OAAO,EACL,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,GASZ,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,WAAW,EACX,WAAW,EACX,KAAK,GAMN,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,IAAI,EAAkB,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,IAAI,EAA4B,MAAM,QAAQ,CAAA;AACvD,OAAO,EAAE,OAAO,EAAqB,MAAM,WAAW,CAAA;AAEtD,OAAO,EACL,OAAO,EACP,UAAU,GAIX,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/chat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAsB,MAAM,YAAY,CAAA;AAC9D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAgC,MAAM,WAAW,CAAA;AACxE,OAAO,EAAE,MAAM,EAAoB,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAa,MAAM,QAAQ,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAc,MAAM,SAAS,CAAA;AAEnD,OAAO,EACL,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,GASZ,MAAM,WAAW,CAAA;AAElB,OAAO,EACL,MAAM,EACN,YAAY,EACZ,WAAW,EACX,WAAW,EACX,KAAK,GAMN,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAE,IAAI,EAAkB,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,IAAI,EAA4B,MAAM,QAAQ,CAAA;AACvD,OAAO,EAAE,OAAO,EAAqB,MAAM,WAAW,CAAA;AAEtD,OAAO,EACL,OAAO,EACP,UAAU,GAIX,MAAM,WAAW,CAAA"}