anentrypoint-design 0.0.385 → 0.0.387

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 (71) hide show
  1. package/dist/247420.css +33 -0
  2. package/dist/247420.js +53 -51
  3. package/package.json +1 -1
  4. package/src/components/agent-chat/controls.js +143 -0
  5. package/src/components/agent-chat/empty-state.js +63 -0
  6. package/src/components/agent-chat/message-rows.js +141 -0
  7. package/src/components/agent-chat/surface.js +206 -0
  8. package/src/components/agent-chat/thread-behaviour.js +50 -0
  9. package/src/components/agent-chat.js +6 -546
  10. package/src/components/chat/composer-affordances.js +109 -0
  11. package/src/components/chat/composer.js +256 -0
  12. package/src/components/chat/threads.js +105 -0
  13. package/src/components/chat-message-parts/agent-nodes.js +103 -0
  14. package/src/components/chat-message-parts/inline.js +106 -0
  15. package/src/components/chat-message-parts/prose-nodes.js +133 -0
  16. package/src/components/chat-message-parts/renderers.js +89 -0
  17. package/src/components/chat-message-parts.js +12 -408
  18. package/src/components/chat-minimap/minimap.js +167 -0
  19. package/src/components/chat-minimap/paint.js +73 -0
  20. package/src/components/chat-minimap/preview.js +41 -0
  21. package/src/components/chat-minimap.js +7 -263
  22. package/src/components/chat.js +20 -628
  23. package/src/components/community/chrome.js +63 -0
  24. package/src/components/community/navigation.js +167 -0
  25. package/src/components/community/presence.js +106 -0
  26. package/src/components/community/shell.js +17 -0
  27. package/src/components/community/views.js +131 -0
  28. package/src/components/community.js +18 -447
  29. package/src/components/files/chrome.js +140 -0
  30. package/src/components/files/entries.js +156 -0
  31. package/src/components/files/grid-controls.js +63 -0
  32. package/src/components/files/grid.js +177 -0
  33. package/src/components/files/types.js +69 -0
  34. package/src/components/files-modals/dialogs.js +118 -0
  35. package/src/components/files-modals/modal-shell.js +153 -0
  36. package/src/components/files-modals/preview-bodies.js +129 -0
  37. package/src/components/files-modals/preview-containers.js +96 -0
  38. package/src/components/files-modals.js +14 -475
  39. package/src/components/files.js +15 -564
  40. package/src/components/freddie/pages-config.js +3 -94
  41. package/src/components/freddie/pages-models.js +97 -0
  42. package/src/components/freddie.js +2 -1
  43. package/src/components/interaction-primitives/mobile.js +25 -0
  44. package/src/components/interaction-primitives/pointer.js +214 -0
  45. package/src/components/interaction-primitives/reorderable.js +47 -0
  46. package/src/components/interaction-primitives/shortcuts.js +119 -0
  47. package/src/components/interaction-primitives.js +16 -388
  48. package/src/components/sessions/conversation-list.js +230 -0
  49. package/src/components/sessions/dashboard.js +202 -0
  50. package/src/components/sessions/detail-bits.js +49 -0
  51. package/src/components/sessions/format.js +42 -0
  52. package/src/components/sessions/session-card.js +92 -0
  53. package/src/components/sessions.js +16 -579
  54. package/src/components/voice/audio-cue.js +39 -0
  55. package/src/components/voice/capture.js +90 -0
  56. package/src/components/voice/playback.js +75 -0
  57. package/src/components/voice/settings-modal.js +104 -0
  58. package/src/components/voice.js +16 -293
  59. package/src/css/app-shell/base.css +23 -0
  60. package/src/css/app-shell/states-interactions.css +10 -0
  61. package/src/kits/os/freddie/chat-protocol.js +32 -0
  62. package/src/kits/os/freddie/chat-transport.js +178 -0
  63. package/src/kits/os/freddie/pages-chat.js +10 -180
  64. package/src/kits/os/shell-chrome.js +163 -0
  65. package/src/kits/os/shell-geometry.js +59 -0
  66. package/src/kits/os/shell.js +178 -335
  67. package/src/page-html/client-script.js +151 -0
  68. package/src/page-html/head-tags.js +59 -0
  69. package/src/page-html/markdown.js +68 -0
  70. package/src/page-html/page-styles.js +44 -0
  71. package/src/page-html.js +14 -291
@@ -0,0 +1,73 @@
1
+ // Pure DOM paint: rebuilds the minimap's children from current `state`. Kept
2
+ // outside webjsx's own vdom diff (this subtree is imperative, like a canvas)
3
+ // because dot count/positions and hover/tooltip visibility change far more
4
+ // often than a full component re-render is warranted for.
5
+
6
+ import { messagePreview } from './preview.js';
7
+
8
+ const TOOLTIP_HEIGHT = 22;
9
+ const TOOLTIP_GAP = 2;
10
+ const TOOLTIP_WIDTH = 200;
11
+
12
+ export function paintMinimap(el, state, messages, width) {
13
+ el.style.display = state.visible ? '' : 'none';
14
+ el.innerHTML = '';
15
+ if (!state.visible) return;
16
+
17
+ const viewportBox = document.createElement('div');
18
+ viewportBox.className = 'chat-minimap-viewport';
19
+ viewportBox.style.top = (state.scrollRatio * (1 - state.viewportRatio) * 100) + '%';
20
+ viewportBox.style.height = (state.viewportRatio * 100) + '%';
21
+ el.appendChild(viewportBox);
22
+
23
+ const centerLine = document.createElement('div');
24
+ centerLine.className = 'chat-minimap-centerline';
25
+ el.appendChild(centerLine);
26
+
27
+ const nodes = state.nodes;
28
+ let nearestIndex = null;
29
+ if (state.mouseYRatio != null && nodes.length) {
30
+ let best = 0;
31
+ for (let i = 1; i < nodes.length; i++) {
32
+ if (Math.abs(nodes[i].topRatio - state.mouseYRatio) < Math.abs(nodes[best].topRatio - state.mouseYRatio)) best = i;
33
+ }
34
+ nearestIndex = nodes[best].index;
35
+ }
36
+
37
+ for (const node of nodes) {
38
+ const dot = document.createElement('div');
39
+ const isUser = node.msg && node.msg.role === 'user';
40
+ dot.className = 'chat-minimap-dot ' + (isUser ? 'is-user' : 'is-assistant') + (state.hovered && nearestIndex === node.index ? ' is-nearest' : '');
41
+ dot.style.top = (node.topRatio * 100) + '%';
42
+ el.appendChild(dot);
43
+ }
44
+
45
+ if (state.hovered && nodes.length) {
46
+ const minimapHeightPx = el.clientHeight || 600;
47
+ const positions = nodes.map((n) => Math.round(n.topRatio * minimapHeightPx - TOOLTIP_HEIGHT / 2));
48
+ for (let pass = 0; pass < 10; pass++) {
49
+ for (let i = 1; i < positions.length; i++) {
50
+ const minTop = positions[i - 1] + TOOLTIP_HEIGHT + TOOLTIP_GAP;
51
+ if (positions[i] < minTop) positions[i] = minTop;
52
+ }
53
+ for (let i = positions.length - 2; i >= 0; i--) {
54
+ const maxTop = positions[i + 1] - TOOLTIP_HEIGHT - TOOLTIP_GAP;
55
+ if (positions[i] > maxTop) positions[i] = maxTop;
56
+ }
57
+ }
58
+ for (let i = 0; i < positions.length; i++) {
59
+ positions[i] = Math.max(0, Math.min(minimapHeightPx - TOOLTIP_HEIGHT, positions[i]));
60
+ }
61
+ nodes.forEach((node, i) => {
62
+ const preview = messagePreview(node.msg);
63
+ if (!preview) return;
64
+ const isNearest = nearestIndex === node.index;
65
+ const tip = document.createElement('div');
66
+ tip.className = 'chat-minimap-tooltip' + (isNearest ? ' is-nearest' : '') + (node.msg.role === 'user' ? ' is-user' : ' is-assistant');
67
+ tip.style.top = positions[i] + 'px';
68
+ tip.style.width = TOOLTIP_WIDTH + 'px';
69
+ tip.textContent = preview;
70
+ el.appendChild(tip);
71
+ });
72
+ }
73
+ }
@@ -0,0 +1,41 @@
1
+ // Message-shape helpers the minimap measures and labels against: preview-text
2
+ // extraction across the three message shapes this kit carries, the has-text
3
+ // and mapped-role filters that decide which turns get a dot, and the message
4
+ // element resolver.
5
+
6
+ export const PREVIEW_CHARS = 200;
7
+
8
+ // Extract a short preview string the same way upstream's getMessagePreview
9
+ // does: prefer flat `text`, then `content` (string or array-of-parts), then
10
+ // `parts` (this kit's structured shape) joined and trimmed.
11
+ export function messagePreview(m) {
12
+ if (!m) return '';
13
+ if (typeof m.text === 'string' && m.text) return m.text.slice(0, PREVIEW_CHARS);
14
+ if (typeof m.content === 'string' && m.content) return m.content.slice(0, PREVIEW_CHARS);
15
+ const partsSrc = Array.isArray(m.content) ? m.content : (Array.isArray(m.parts) ? m.parts : null);
16
+ if (partsSrc) {
17
+ const joined = partsSrc
18
+ .map((p) => (typeof p === 'string' ? p : (p && (p.text || (p.type === 'text' && p.text)) || '')))
19
+ .filter(Boolean)
20
+ .join(' ');
21
+ if (joined) return joined.slice(0, PREVIEW_CHARS);
22
+ }
23
+ return '';
24
+ }
25
+
26
+ // True when a message carries any renderable text (dots skip empty/tool-only
27
+ // turns the way upstream's hasTextContent does).
28
+ export function hasTextContent(m) {
29
+ return !!messagePreview(m);
30
+ }
31
+
32
+ export function isMappedRole(role) {
33
+ return role === 'user' || role === 'assistant';
34
+ }
35
+
36
+ // Resolve the DOM node for message index `i`, via the host's getter or the
37
+ // data-msg-index fallback.
38
+ export function resolveMessageEl(threadEl, getMessageEl, i) {
39
+ if (typeof getMessageEl === 'function') return getMessageEl(i) || null;
40
+ return threadEl.querySelector('[data-msg-index="' + i + '"]') || null;
41
+ }
@@ -42,268 +42,12 @@
42
42
  // omitted, so a host that tags its message rows with
43
43
  // data-msg-index="N" needs no extra wiring.
44
44
  // width : minimap strip width in px (default 36, matches upstream).
45
- export const CHAT_MINIMAP_WIDTH = 36;
46
- const MEASURE_THROTTLE_MS = 150;
47
- const TOOLTIP_HEIGHT = 22;
48
- const TOOLTIP_GAP = 2;
49
- const TOOLTIP_WIDTH = 200;
50
- const PREVIEW_CHARS = 200;
51
- const MIN_SCROLLABLE_PX = 20;
52
-
53
- import * as webjsx from '../../vendor/webjsx/index.js';
54
- const h = webjsx.createElement;
55
-
56
- // Extract a short preview string the same way upstream's getMessagePreview
57
- // does: prefer flat `text`, then `content` (string or array-of-parts), then
58
- // `parts` (this kit's structured shape) joined and trimmed.
59
- function messagePreview(m) {
60
- if (!m) return '';
61
- if (typeof m.text === 'string' && m.text) return m.text.slice(0, PREVIEW_CHARS);
62
- if (typeof m.content === 'string' && m.content) return m.content.slice(0, PREVIEW_CHARS);
63
- const partsSrc = Array.isArray(m.content) ? m.content : (Array.isArray(m.parts) ? m.parts : null);
64
- if (partsSrc) {
65
- const joined = partsSrc
66
- .map((p) => (typeof p === 'string' ? p : (p && (p.text || (p.type === 'text' && p.text)) || '')))
67
- .filter(Boolean)
68
- .join(' ');
69
- if (joined) return joined.slice(0, PREVIEW_CHARS);
70
- }
71
- return '';
72
- }
73
-
74
- // True when a message carries any renderable text (dots skip empty/tool-only
75
- // turns the way upstream's hasTextContent does).
76
- function hasTextContent(m) {
77
- return !!messagePreview(m);
78
- }
79
-
80
- function isMappedRole(role) {
81
- return role === 'user' || role === 'assistant';
82
- }
83
-
84
- // Resolve the DOM node for message index `i`, via the host's getter or the
85
- // data-msg-index fallback.
86
- function resolveMessageEl(threadEl, getMessageEl, i) {
87
- if (typeof getMessageEl === 'function') return getMessageEl(i) || null;
88
- return threadEl.querySelector('[data-msg-index="' + i + '"]') || null;
89
- }
90
-
91
- export function ChatMinimap({ messages = [], getThreadEl, getMessageEl, width = CHAT_MINIMAP_WIDTH } = {}) {
92
- // All mutable state lives on the container element itself (webjsx factories
93
- // are pure-render; the ref callback owns the imperative lifecycle, same
94
- // pattern as makeThreadAutoScroll in chat.js).
95
- const state = {
96
- scrollRatio: 0,
97
- viewportRatio: 1,
98
- visible: false,
99
- nodes: /** @type {Array<{topRatio:number, heightRatio:number, msg:any, index:number}>} */ ([]),
100
- hovered: false,
101
- mouseYRatio: null,
102
- };
103
-
104
- const containerRef = (el) => {
105
- if (!el) return;
106
- if (el._dsMinimapCleanup) return; // already wired for this DOM node
107
- let measureTimer = null;
108
- let ro = null;
109
- let threadEl = null;
110
- let scrollListenerEl = null;
111
-
112
- const render = () => paintMinimap(el, state, messages, width);
113
-
114
- const updateScroll = () => {
115
- const t = typeof getThreadEl === 'function' ? getThreadEl() : null;
116
- if (!t) return;
117
- const totalH = t.scrollHeight;
118
- const clientH = t.clientHeight;
119
- const scrollable = totalH - clientH;
120
- state.visible = scrollable > MIN_SCROLLABLE_PX;
121
- if (scrollable <= 0) {
122
- state.scrollRatio = 0;
123
- state.viewportRatio = 1;
124
- } else {
125
- state.scrollRatio = t.scrollTop / scrollable;
126
- state.viewportRatio = clientH / totalH;
127
- }
128
- render();
129
- };
130
-
131
- const measureNodes = () => {
132
- if (measureTimer) return; // throttled — one pending pass at a time
133
- measureTimer = setTimeout(() => {
134
- measureTimer = null;
135
- const t = typeof getThreadEl === 'function' ? getThreadEl() : null;
136
- if (!t) return;
137
- const totalH = t.scrollHeight;
138
- if (totalH <= 0) return;
139
- const containerRect = t.getBoundingClientRect();
140
- const newNodes = [];
141
- for (let i = 0; i < messages.length; i++) {
142
- const msg = messages[i];
143
- if (!isMappedRole(msg && msg.role)) continue;
144
- if (!hasTextContent(msg)) continue;
145
- const msgEl = resolveMessageEl(t, getMessageEl, i);
146
- if (!msgEl) continue;
147
- const elRect = msgEl.getBoundingClientRect();
148
- const top = elRect.top - containerRect.top + t.scrollTop;
149
- newNodes.push({
150
- topRatio: top / totalH,
151
- heightRatio: elRect.height / totalH,
152
- msg,
153
- index: newNodes.length,
154
- });
155
- }
156
- state.nodes = newNodes;
157
- render();
158
- }, MEASURE_THROTTLE_MS);
159
- };
160
-
161
- const syncLayout = () => { updateScroll(); measureNodes(); };
162
-
163
- // Rebinds scroll listener + ResizeObserver to whichever thread element
164
- // getThreadEl currently resolves to (it may be null on first paint and
165
- // become available once the thread's own ref fires).
166
- const rebind = () => {
167
- const t = typeof getThreadEl === 'function' ? getThreadEl() : null;
168
- if (t === threadEl) return;
169
- if (scrollListenerEl) scrollListenerEl.removeEventListener('scroll', updateScroll);
170
- if (ro) { ro.disconnect(); ro = null; }
171
- threadEl = t;
172
- scrollListenerEl = t;
173
- if (!t) return;
174
- t.addEventListener('scroll', updateScroll, { passive: true });
175
- ro = new ResizeObserver(syncLayout);
176
- ro.observe(t);
177
- if (t.firstElementChild) ro.observe(t.firstElementChild);
178
- syncLayout();
179
- };
180
- rebind();
181
- // Thread element may not exist yet on first mount; poll briefly (mirrors
182
- // upstream's 50ms post-message-change settle) until it appears, then the
183
- // ResizeObserver takes over for everything after.
184
- const rebindPoll = setInterval(rebind, 200);
185
-
186
- // Drag-to-scroll + click-to-jump on the strip itself.
187
- let dragging = false;
188
- const scrollToRatio = (viewportTopRatio) => {
189
- const t = typeof getThreadEl === 'function' ? getThreadEl() : null;
190
- if (!t) return;
191
- const scrollable = t.scrollHeight - t.clientHeight;
192
- if (scrollable <= 0) return;
193
- const clamped = Math.max(0, Math.min(1 - state.viewportRatio, viewportTopRatio));
194
- t.scrollTop = (clamped / (1 - state.viewportRatio)) * scrollable;
195
- };
196
- const ratioFromEvent = (ev) => {
197
- const rect = el.getBoundingClientRect();
198
- return (ev.clientY - rect.top) / rect.height;
199
- };
200
- const onMouseDown = (ev) => {
201
- if (!state.visible) return;
202
- dragging = true;
203
- const clickRatio = ratioFromEvent(ev);
204
- const grabOffset = clickRatio - state.scrollRatio * (1 - state.viewportRatio);
205
- const insideBox = grabOffset >= 0 && grabOffset <= state.viewportRatio;
206
- const offset = insideBox ? grabOffset : state.viewportRatio / 2;
207
- scrollToRatio(clickRatio - offset);
208
- const onMove = (mv) => { if (dragging) scrollToRatio(ratioFromEvent(mv) - offset); };
209
- const onUp = () => { dragging = false; window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); };
210
- window.addEventListener('mousemove', onMove);
211
- window.addEventListener('mouseup', onUp);
212
- };
213
- const onMouseEnter = () => { state.hovered = true; render(); };
214
- const onMouseLeave = () => { state.hovered = false; state.mouseYRatio = null; render(); };
215
- const onMouseMove = (ev) => { state.mouseYRatio = ratioFromEvent(ev); render(); };
216
- el.addEventListener('mousedown', onMouseDown);
217
- el.addEventListener('mouseenter', onMouseEnter);
218
- el.addEventListener('mouseleave', onMouseLeave);
219
- el.addEventListener('mousemove', onMouseMove);
220
-
221
- el._dsMinimapCleanup = () => {
222
- clearInterval(rebindPoll);
223
- if (measureTimer) clearTimeout(measureTimer);
224
- if (scrollListenerEl) scrollListenerEl.removeEventListener('scroll', updateScroll);
225
- if (ro) ro.disconnect();
226
- el.removeEventListener('mousedown', onMouseDown);
227
- el.removeEventListener('mouseenter', onMouseEnter);
228
- el.removeEventListener('mouseleave', onMouseLeave);
229
- el.removeEventListener('mousemove', onMouseMove);
230
- };
231
-
232
- render();
233
- };
234
-
235
- return h('div', {
236
- class: 'chat-minimap',
237
- ref: containerRef,
238
- role: 'navigation',
239
- 'aria-label': 'conversation scroll overview',
240
- style: 'width:' + width + 'px',
241
- });
242
- }
243
-
244
- // Pure DOM paint: rebuilds the minimap's children from current `state`. Kept
245
- // outside webjsx's own vdom diff (this subtree is imperative, like a canvas)
246
- // because dot count/positions and hover/tooltip visibility change far more
247
- // often than a full component re-render is warranted for.
248
- function paintMinimap(el, state, messages, width) {
249
- el.style.display = state.visible ? '' : 'none';
250
- el.innerHTML = '';
251
- if (!state.visible) return;
252
-
253
- const viewportBox = document.createElement('div');
254
- viewportBox.className = 'chat-minimap-viewport';
255
- viewportBox.style.top = (state.scrollRatio * (1 - state.viewportRatio) * 100) + '%';
256
- viewportBox.style.height = (state.viewportRatio * 100) + '%';
257
- el.appendChild(viewportBox);
258
-
259
- const centerLine = document.createElement('div');
260
- centerLine.className = 'chat-minimap-centerline';
261
- el.appendChild(centerLine);
262
-
263
- const nodes = state.nodes;
264
- let nearestIndex = null;
265
- if (state.mouseYRatio != null && nodes.length) {
266
- let best = 0;
267
- for (let i = 1; i < nodes.length; i++) {
268
- if (Math.abs(nodes[i].topRatio - state.mouseYRatio) < Math.abs(nodes[best].topRatio - state.mouseYRatio)) best = i;
269
- }
270
- nearestIndex = nodes[best].index;
271
- }
45
+ //
46
+ // This module is a barrel: the message-shape helpers, the imperative paint,
47
+ // and the component's own lifecycle live in single-responsibility submodules
48
+ // under ./chat-minimap/, and the public export surface here is unchanged —
49
+ // no consumer import needs to move.
272
50
 
273
- for (const node of nodes) {
274
- const dot = document.createElement('div');
275
- const isUser = node.msg && node.msg.role === 'user';
276
- dot.className = 'chat-minimap-dot ' + (isUser ? 'is-user' : 'is-assistant') + (state.hovered && nearestIndex === node.index ? ' is-nearest' : '');
277
- dot.style.top = (node.topRatio * 100) + '%';
278
- el.appendChild(dot);
279
- }
51
+ import { ChatMinimap, CHAT_MINIMAP_WIDTH } from './chat-minimap/minimap.js';
280
52
 
281
- if (state.hovered && nodes.length) {
282
- const minimapHeightPx = el.clientHeight || 600;
283
- const positions = nodes.map((n) => Math.round(n.topRatio * minimapHeightPx - TOOLTIP_HEIGHT / 2));
284
- for (let pass = 0; pass < 10; pass++) {
285
- for (let i = 1; i < positions.length; i++) {
286
- const minTop = positions[i - 1] + TOOLTIP_HEIGHT + TOOLTIP_GAP;
287
- if (positions[i] < minTop) positions[i] = minTop;
288
- }
289
- for (let i = positions.length - 2; i >= 0; i--) {
290
- const maxTop = positions[i + 1] - TOOLTIP_HEIGHT - TOOLTIP_GAP;
291
- if (positions[i] > maxTop) positions[i] = maxTop;
292
- }
293
- }
294
- for (let i = 0; i < positions.length; i++) {
295
- positions[i] = Math.max(0, Math.min(minimapHeightPx - TOOLTIP_HEIGHT, positions[i]));
296
- }
297
- nodes.forEach((node, i) => {
298
- const preview = messagePreview(node.msg);
299
- if (!preview) return;
300
- const isNearest = nearestIndex === node.index;
301
- const tip = document.createElement('div');
302
- tip.className = 'chat-minimap-tooltip' + (isNearest ? ' is-nearest' : '') + (node.msg.role === 'user' ? ' is-user' : ' is-assistant');
303
- tip.style.top = positions[i] + 'px';
304
- tip.style.width = TOOLTIP_WIDTH + 'px';
305
- tip.textContent = preview;
306
- el.appendChild(tip);
307
- });
308
- }
309
- }
53
+ export { ChatMinimap, CHAT_MINIMAP_WIDTH };