@4djs/assistant 0.0.0 → 0.1.0

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 (189) hide show
  1. package/README.md +49 -68
  2. package/dist/core/chat-activity.d.ts +19 -0
  3. package/dist/core/chat-activity.d.ts.map +1 -0
  4. package/dist/core/chat-commands.d.ts +33 -0
  5. package/dist/core/chat-commands.d.ts.map +1 -0
  6. package/dist/core/chat-history.d.ts +14 -0
  7. package/dist/core/chat-history.d.ts.map +1 -0
  8. package/dist/core/chat-reply-suggestions-parse.d.ts +20 -0
  9. package/dist/core/chat-reply-suggestions-parse.d.ts.map +1 -0
  10. package/dist/core/code-highlight.d.ts +3 -0
  11. package/dist/core/code-highlight.d.ts.map +1 -0
  12. package/dist/core/create-assistant-store.d.ts +33 -0
  13. package/dist/core/create-assistant-store.d.ts.map +1 -0
  14. package/dist/core/fetch-suggested-prompts.d.ts +11 -0
  15. package/dist/core/fetch-suggested-prompts.d.ts.map +1 -0
  16. package/dist/core/index.d.ts +19 -0
  17. package/dist/core/index.d.ts.map +1 -0
  18. package/dist/core/index.js +2876 -0
  19. package/dist/core/interactive-tools/choices.d.ts +22 -0
  20. package/dist/core/interactive-tools/choices.d.ts.map +1 -0
  21. package/dist/core/interactive-tools/confirmation.d.ts +15 -0
  22. package/dist/core/interactive-tools/confirmation.d.ts.map +1 -0
  23. package/dist/core/interactive-tools/constants.d.ts +6 -0
  24. package/dist/core/interactive-tools/constants.d.ts.map +1 -0
  25. package/dist/core/interactive-tools/execute.d.ts +11 -0
  26. package/dist/core/interactive-tools/execute.d.ts.map +1 -0
  27. package/dist/core/interactive-tools/index.d.ts +7 -0
  28. package/dist/core/interactive-tools/index.d.ts.map +1 -0
  29. package/dist/core/interactive-tools/suggestions.d.ts +13 -0
  30. package/dist/core/interactive-tools/suggestions.d.ts.map +1 -0
  31. package/dist/core/interactive-tools/waiters.d.ts +4 -0
  32. package/dist/core/interactive-tools/waiters.d.ts.map +1 -0
  33. package/dist/core/llm-chat.d.ts +96 -0
  34. package/dist/core/llm-chat.d.ts.map +1 -0
  35. package/dist/core/llm-config.d.ts +24 -0
  36. package/dist/core/llm-config.d.ts.map +1 -0
  37. package/dist/core/llm-models.d.ts +14 -0
  38. package/dist/core/llm-models.d.ts.map +1 -0
  39. package/dist/core/llm-provider.d.ts +13 -0
  40. package/dist/core/llm-provider.d.ts.map +1 -0
  41. package/dist/core/llm-settings-storage.d.ts +47 -0
  42. package/dist/core/llm-settings-storage.d.ts.map +1 -0
  43. package/dist/core/llm-sse.d.ts +13 -0
  44. package/dist/core/llm-sse.d.ts.map +1 -0
  45. package/dist/core/llm-types.d.ts +49 -0
  46. package/dist/core/llm-types.d.ts.map +1 -0
  47. package/dist/core/markdown-utils.d.ts +3 -0
  48. package/dist/core/markdown-utils.d.ts.map +1 -0
  49. package/dist/core/prepare-markdown.d.ts +7 -0
  50. package/dist/core/prepare-markdown.d.ts.map +1 -0
  51. package/dist/core/types.d.ts +74 -0
  52. package/dist/core/types.d.ts.map +1 -0
  53. package/dist/index.css +1195 -0
  54. package/dist/index.js +184948 -0
  55. package/dist/react/Assistant.d.ts +10 -0
  56. package/dist/react/Assistant.d.ts.map +1 -0
  57. package/dist/react/components/HighlightedJsonCode.d.ts +6 -0
  58. package/dist/react/components/HighlightedJsonCode.d.ts.map +1 -0
  59. package/dist/react/components/MarkdownContent.d.ts +10 -0
  60. package/dist/react/components/MarkdownContent.d.ts.map +1 -0
  61. package/dist/react/components/MarkdownEditor.d.ts +11 -0
  62. package/dist/react/components/MarkdownEditor.d.ts.map +1 -0
  63. package/dist/react/components/MermaidDiagram.d.ts +8 -0
  64. package/dist/react/components/MermaidDiagram.d.ts.map +1 -0
  65. package/dist/react/components/ModelSelector.d.ts +8 -0
  66. package/dist/react/components/ModelSelector.d.ts.map +1 -0
  67. package/dist/react/components/chat/AssistantErrorCallout.d.ts +11 -0
  68. package/dist/react/components/chat/AssistantErrorCallout.d.ts.map +1 -0
  69. package/dist/react/components/chat/ChatActivity.d.ts +8 -0
  70. package/dist/react/components/chat/ChatActivity.d.ts.map +1 -0
  71. package/dist/react/components/chat/ChatComposer.d.ts +36 -0
  72. package/dist/react/components/chat/ChatComposer.d.ts.map +1 -0
  73. package/dist/react/components/chat/ChatEmptyState.d.ts +10 -0
  74. package/dist/react/components/chat/ChatEmptyState.d.ts.map +1 -0
  75. package/dist/react/components/chat/ChatInteractivePrompt/choices-prompt.d.ts +7 -0
  76. package/dist/react/components/chat/ChatInteractivePrompt/choices-prompt.d.ts.map +1 -0
  77. package/dist/react/components/chat/ChatInteractivePrompt/confirmation-prompt.d.ts +7 -0
  78. package/dist/react/components/chat/ChatInteractivePrompt/confirmation-prompt.d.ts.map +1 -0
  79. package/dist/react/components/chat/ChatInteractivePrompt/index.d.ts +7 -0
  80. package/dist/react/components/chat/ChatInteractivePrompt/index.d.ts.map +1 -0
  81. package/dist/react/components/chat/ChatInteractivePrompt/shell.d.ts +13 -0
  82. package/dist/react/components/chat/ChatInteractivePrompt/shell.d.ts.map +1 -0
  83. package/dist/react/components/chat/ChatInteractivePrompt/utils.d.ts +4 -0
  84. package/dist/react/components/chat/ChatInteractivePrompt/utils.d.ts.map +1 -0
  85. package/dist/react/components/chat/ChatMessage.d.ts +11 -0
  86. package/dist/react/components/chat/ChatMessage.d.ts.map +1 -0
  87. package/dist/react/components/chat/ChatMessageScroll.d.ts +8 -0
  88. package/dist/react/components/chat/ChatMessageScroll.d.ts.map +1 -0
  89. package/dist/react/components/chat/ChatReplySuggestions.d.ts +9 -0
  90. package/dist/react/components/chat/ChatReplySuggestions.d.ts.map +1 -0
  91. package/dist/react/components/chat/ComposerCommandMenu.d.ts +10 -0
  92. package/dist/react/components/chat/ComposerCommandMenu.d.ts.map +1 -0
  93. package/dist/react/components/chat/LlmSettingsStrip.d.ts +7 -0
  94. package/dist/react/components/chat/LlmSettingsStrip.d.ts.map +1 -0
  95. package/dist/react/components/chat/LlmSetupPrompt.d.ts +7 -0
  96. package/dist/react/components/chat/LlmSetupPrompt.d.ts.map +1 -0
  97. package/dist/react/components/chat/LlmUnavailableBanner.d.ts +6 -0
  98. package/dist/react/components/chat/LlmUnavailableBanner.d.ts.map +1 -0
  99. package/dist/react/components/chat/SuggestedPromptsList.d.ts +14 -0
  100. package/dist/react/components/chat/SuggestedPromptsList.d.ts.map +1 -0
  101. package/dist/react/components/chat/SuggestedPromptsStrip.d.ts +11 -0
  102. package/dist/react/components/chat/SuggestedPromptsStrip.d.ts.map +1 -0
  103. package/dist/react/components/chat/SystemPromptField.d.ts +10 -0
  104. package/dist/react/components/chat/SystemPromptField.d.ts.map +1 -0
  105. package/dist/react/components/highlighted-code.d.ts +8 -0
  106. package/dist/react/components/highlighted-code.d.ts.map +1 -0
  107. package/dist/react/context.d.ts +11 -0
  108. package/dist/react/context.d.ts.map +1 -0
  109. package/dist/react/hooks/use-composer-commands.d.ts +21 -0
  110. package/dist/react/hooks/use-composer-commands.d.ts.map +1 -0
  111. package/dist/react/hooks/use-suggested-prompts.d.ts +29 -0
  112. package/dist/react/hooks/use-suggested-prompts.d.ts.map +1 -0
  113. package/dist/react/index.d.ts +17 -0
  114. package/dist/react/index.d.ts.map +1 -0
  115. package/dist/react/lib/parse-assistant-error.d.ts +9 -0
  116. package/dist/react/lib/parse-assistant-error.d.ts.map +1 -0
  117. package/dist/react/lib/prompt-icons.d.ts +5 -0
  118. package/dist/react/lib/prompt-icons.d.ts.map +1 -0
  119. package/dist/react/types.d.ts +69 -0
  120. package/dist/react/types.d.ts.map +1 -0
  121. package/dist/react/utils/cn.d.ts +2 -0
  122. package/dist/react/utils/cn.d.ts.map +1 -0
  123. package/package.json +16 -5
  124. package/src/core/chat-activity.ts +0 -107
  125. package/src/core/chat-commands.ts +0 -173
  126. package/src/core/chat-history.ts +0 -113
  127. package/src/core/chat-reply-suggestions-parse.ts +0 -119
  128. package/src/core/code-highlight.ts +0 -20
  129. package/src/core/create-assistant-store.ts +0 -639
  130. package/src/core/fetch-suggested-prompts.ts +0 -53
  131. package/src/core/index.ts +0 -125
  132. package/src/core/interactive-tools/choices.ts +0 -155
  133. package/src/core/interactive-tools/confirmation.ts +0 -63
  134. package/src/core/interactive-tools/constants.ts +0 -22
  135. package/src/core/interactive-tools/execute.ts +0 -70
  136. package/src/core/interactive-tools/index.ts +0 -41
  137. package/src/core/interactive-tools/suggestions.ts +0 -87
  138. package/src/core/interactive-tools/waiters.ts +0 -55
  139. package/src/core/llm-chat.ts +0 -686
  140. package/src/core/llm-config.ts +0 -101
  141. package/src/core/llm-models.ts +0 -96
  142. package/src/core/llm-provider.ts +0 -99
  143. package/src/core/llm-settings-storage.ts +0 -331
  144. package/src/core/llm-sse.ts +0 -166
  145. package/src/core/llm-types.ts +0 -52
  146. package/src/core/markdown-utils.ts +0 -11
  147. package/src/core/prepare-markdown.ts +0 -38
  148. package/src/core/types.ts +0 -86
  149. package/src/css.d.ts +0 -1
  150. package/src/react/Assistant.tsx +0 -358
  151. package/src/react/components/HighlightedJsonCode.tsx +0 -24
  152. package/src/react/components/MarkdownContent.tsx +0 -98
  153. package/src/react/components/MarkdownEditor.tsx +0 -60
  154. package/src/react/components/MermaidDiagram.tsx +0 -139
  155. package/src/react/components/ModelSelector.tsx +0 -243
  156. package/src/react/components/chat/AssistantErrorCallout.tsx +0 -79
  157. package/src/react/components/chat/ChatActivity.tsx +0 -274
  158. package/src/react/components/chat/ChatComposer.tsx +0 -189
  159. package/src/react/components/chat/ChatEmptyState.tsx +0 -145
  160. package/src/react/components/chat/ChatInteractivePrompt/choices-prompt.tsx +0 -262
  161. package/src/react/components/chat/ChatInteractivePrompt/confirmation-prompt.tsx +0 -97
  162. package/src/react/components/chat/ChatInteractivePrompt/index.tsx +0 -60
  163. package/src/react/components/chat/ChatInteractivePrompt/shell.tsx +0 -60
  164. package/src/react/components/chat/ChatInteractivePrompt/utils.ts +0 -14
  165. package/src/react/components/chat/ChatMessage.tsx +0 -150
  166. package/src/react/components/chat/ChatMessageScroll.tsx +0 -116
  167. package/src/react/components/chat/ChatReplySuggestions.tsx +0 -231
  168. package/src/react/components/chat/ComposerCommandMenu.tsx +0 -69
  169. package/src/react/components/chat/LlmSettingsStrip.tsx +0 -348
  170. package/src/react/components/chat/LlmSetupPrompt.tsx +0 -58
  171. package/src/react/components/chat/LlmUnavailableBanner.tsx +0 -11
  172. package/src/react/components/chat/SuggestedPromptsList.tsx +0 -121
  173. package/src/react/components/chat/SuggestedPromptsStrip.tsx +0 -72
  174. package/src/react/components/chat/SystemPromptField.tsx +0 -107
  175. package/src/react/components/highlighted-code.tsx +0 -107
  176. package/src/react/context.tsx +0 -72
  177. package/src/react/hooks/use-composer-commands.ts +0 -129
  178. package/src/react/hooks/use-suggested-prompts.ts +0 -128
  179. package/src/react/index.ts +0 -39
  180. package/src/react/lib/parse-assistant-error.ts +0 -96
  181. package/src/react/lib/prompt-icons.ts +0 -40
  182. package/src/react/types.ts +0 -83
  183. package/src/react/utils/cn.ts +0 -5
  184. package/test/buildLlmHistory.test.ts +0 -95
  185. package/test/llm-config.test.ts +0 -72
  186. package/test/llmSettingsStorage.test.ts +0 -121
  187. package/test/parse-assistant-error.test.ts +0 -24
  188. package/tsconfig.json +0 -8
  189. /package/{src/styles/assistant.css → dist/styles.css} +0 -0
@@ -1,116 +0,0 @@
1
- import { ArrowDown } from "lucide-react";
2
- import {
3
- type ReactNode,
4
- useCallback,
5
- useEffect,
6
- useRef,
7
- useState,
8
- } from "react";
9
-
10
- const SCROLL_BOTTOM_THRESHOLD = 48;
11
-
12
- function isNearBottom(viewport: HTMLDivElement): boolean {
13
- return (
14
- viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight <=
15
- SCROLL_BOTTOM_THRESHOLD
16
- );
17
- }
18
-
19
- interface ChatMessageScrollProps {
20
- children: ReactNode;
21
- dependencyKey: string;
22
- }
23
-
24
- export function ChatMessageScroll({
25
- children,
26
- dependencyKey,
27
- }: ChatMessageScrollProps) {
28
- const scrollContainerRef = useRef<HTMLDivElement>(null);
29
- const contentRef = useRef<HTMLDivElement>(null);
30
- const stickToBottomRef = useRef(true);
31
- const [showScrollDown, setShowScrollDown] = useState(false);
32
-
33
- const updateScrollState = useCallback(() => {
34
- const viewport = scrollContainerRef.current;
35
- if (!viewport) return;
36
- const atBottom = isNearBottom(viewport);
37
- setShowScrollDown(!atBottom);
38
- stickToBottomRef.current = atBottom;
39
- }, []);
40
-
41
- const scrollToBottom = useCallback((behavior: ScrollBehavior = "smooth") => {
42
- const viewport = scrollContainerRef.current;
43
- if (!viewport) return;
44
- viewport.scrollTo({ top: viewport.scrollHeight, behavior });
45
- stickToBottomRef.current = true;
46
- setShowScrollDown(false);
47
- }, []);
48
-
49
- const handleContentResize = useCallback(() => {
50
- const viewport = scrollContainerRef.current;
51
- if (!viewport) return;
52
- if (stickToBottomRef.current) {
53
- viewport.scrollTo({ top: viewport.scrollHeight, behavior: "auto" });
54
- setShowScrollDown(false);
55
- return;
56
- }
57
- updateScrollState();
58
- }, [updateScrollState]);
59
-
60
- useEffect(() => {
61
- const content = contentRef.current;
62
- if (!content) return;
63
- const resizeObserver = new ResizeObserver(handleContentResize);
64
- resizeObserver.observe(content);
65
- return () => resizeObserver.disconnect();
66
- }, [handleContentResize]);
67
-
68
- useEffect(() => {
69
- const viewport = scrollContainerRef.current;
70
- if (!viewport) return;
71
- updateScrollState();
72
- viewport.addEventListener("scroll", updateScrollState, { passive: true });
73
- return () => viewport.removeEventListener("scroll", updateScrollState);
74
- }, [updateScrollState]);
75
-
76
- useEffect(() => {
77
- const viewport = scrollContainerRef.current;
78
- if (!viewport) return;
79
- void dependencyKey;
80
- if (!stickToBottomRef.current) {
81
- updateScrollState();
82
- return;
83
- }
84
- viewport.scrollTo({
85
- top: viewport.scrollHeight,
86
- behavior: "auto",
87
- });
88
- setShowScrollDown(false);
89
- }, [dependencyKey, updateScrollState]);
90
-
91
- return (
92
- <div className="relative h-0 min-h-0 flex-1">
93
- <div
94
- ref={scrollContainerRef}
95
- className="h-full overflow-x-hidden overflow-y-auto overscroll-contain bg-[var(--overlay-subtle)]"
96
- aria-live="polite"
97
- >
98
- <div ref={contentRef} className="assistant-message-list">
99
- {children}
100
- <div aria-hidden className="h-px shrink-0" />
101
- </div>
102
- </div>
103
- {showScrollDown ? (
104
- <button
105
- type="button"
106
- className="assistant-scroll-down"
107
- aria-label="Scroll to bottom"
108
- title="Scroll to bottom"
109
- onClick={() => scrollToBottom("smooth")}
110
- >
111
- <ArrowDown size={16} aria-hidden />
112
- </button>
113
- ) : null}
114
- </div>
115
- );
116
- }
@@ -1,231 +0,0 @@
1
- import { ArrowUpRight, PenLine } from "lucide-react";
2
- import { useEffect } from "react";
3
- import {
4
- type ParsedSuggestion,
5
- parseSuggestionText,
6
- splitToolValues,
7
- } from "../../../core/chat-reply-suggestions-parse.ts";
8
- import type { ReplySuggestions } from "../../../core/interactive-tools/index.ts";
9
- import { cn } from "../../utils/cn.ts";
10
-
11
- type ChatReplySuggestionsProps = {
12
- suggestions: ReplySuggestions;
13
- disabled?: boolean;
14
- onSelect: (reply: string) => void;
15
- };
16
-
17
- function fieldBadgeLabel(label: string): string {
18
- switch (label.toLowerCase()) {
19
- case "model":
20
- return "Model";
21
- case "enabled":
22
- return "Status";
23
- case "tools":
24
- return "Tools";
25
- case "dataclass":
26
- return "Dataclass";
27
- case "filter":
28
- return "Filter";
29
- default:
30
- return label;
31
- }
32
- }
33
-
34
- function StructuredSuggestionRow({
35
- suggestion,
36
- index,
37
- disabled,
38
- onSelect,
39
- }: {
40
- suggestion: Extract<ParsedSuggestion, { kind: "structured" }>;
41
- index: number;
42
- disabled?: boolean;
43
- onSelect: () => void;
44
- }) {
45
- const toolsField = suggestion.fields.find(
46
- (field) => field.label.toLowerCase() === "tools",
47
- );
48
- const metaFields = suggestion.fields.filter(
49
- (field) => field.label.toLowerCase() !== "tools",
50
- );
51
- const toolNames = toolsField ? splitToolValues(toolsField.value) : [];
52
-
53
- return (
54
- <button
55
- type="button"
56
- disabled={disabled}
57
- className="assistant-reply-option assistant-reply-option--structured group"
58
- onClick={onSelect}
59
- >
60
- <span className="assistant-reply-option__index" aria-hidden>
61
- {index + 1}
62
- </span>
63
- <span className="assistant-reply-option__body">
64
- <span className="assistant-reply-option__label">
65
- {suggestion.title}
66
- </span>
67
- {suggestion.description ? (
68
- <span className="assistant-reply-option__meta">
69
- {suggestion.description}
70
- </span>
71
- ) : null}
72
- {(metaFields.length > 0 || toolNames.length > 0) && (
73
- <span className="assistant-reply-option__badges">
74
- {metaFields.map((field) => (
75
- <span
76
- key={`${field.label}-${field.value}`}
77
- className="assistant-reply-badge"
78
- >
79
- <span className="assistant-reply-badge__label">
80
- {fieldBadgeLabel(field.label)}
81
- </span>
82
- <span className="assistant-reply-badge__value">
83
- {field.value}
84
- </span>
85
- </span>
86
- ))}
87
- {toolNames.map((tool) => (
88
- <span key={tool} className="assistant-reply-tool">
89
- {tool}
90
- </span>
91
- ))}
92
- </span>
93
- )}
94
- </span>
95
- <ArrowUpRight
96
- className="assistant-reply-option__arrow size-3.5 shrink-0"
97
- aria-hidden
98
- />
99
- </button>
100
- );
101
- }
102
-
103
- function CompactSuggestionRow({
104
- text,
105
- index,
106
- disabled,
107
- custom,
108
- onSelect,
109
- }: {
110
- text: string;
111
- index: number;
112
- disabled?: boolean;
113
- custom?: boolean;
114
- onSelect: () => void;
115
- }) {
116
- return (
117
- <button
118
- type="button"
119
- disabled={disabled}
120
- className={cn(
121
- "assistant-reply-option group",
122
- custom && "assistant-reply-option--custom",
123
- )}
124
- onClick={onSelect}
125
- >
126
- <span className="assistant-reply-option__index" aria-hidden>
127
- {index + 1}
128
- </span>
129
- <span className="assistant-reply-option__body">
130
- {custom ? (
131
- <span className="assistant-reply-option__custom">
132
- <PenLine className="size-3 shrink-0" aria-hidden />
133
- <span>{text}</span>
134
- </span>
135
- ) : (
136
- <span className="assistant-reply-option__label">{text}</span>
137
- )}
138
- </span>
139
- <ArrowUpRight
140
- className="assistant-reply-option__arrow size-3.5 shrink-0"
141
- aria-hidden
142
- />
143
- </button>
144
- );
145
- }
146
-
147
- export function ChatReplySuggestions({
148
- suggestions,
149
- disabled,
150
- onSelect,
151
- }: ChatReplySuggestionsProps) {
152
- const parsed = suggestions.suggestions.map((text) => ({
153
- raw: text,
154
- parsed: parseSuggestionText(text),
155
- }));
156
-
157
- useEffect(() => {
158
- if (disabled) return;
159
-
160
- function onKeyDown(event: KeyboardEvent) {
161
- if (!/^[1-9]$/.test(event.key)) return;
162
-
163
- const index = Number(event.key) - 1;
164
- const target = suggestions.suggestions[index];
165
- if (!target) return;
166
-
167
- const active = document.activeElement;
168
- if (
169
- active instanceof HTMLElement &&
170
- (active.tagName === "INPUT" ||
171
- active.tagName === "TEXTAREA" ||
172
- active.isContentEditable)
173
- ) {
174
- return;
175
- }
176
-
177
- event.preventDefault();
178
- onSelect(target);
179
- }
180
-
181
- window.addEventListener("keydown", onKeyDown);
182
- return () => window.removeEventListener("keydown", onKeyDown);
183
- }, [disabled, onSelect, suggestions.suggestions]);
184
-
185
- return (
186
- <fieldset className="assistant-reply-suggestions border-0 p-0 m-0 min-w-0">
187
- <legend className="sr-only">Suggested replies</legend>
188
- <div className="assistant-reply-suggestions__panel">
189
- <div className="assistant-reply-suggestions__list">
190
- {parsed.map((entry, index) => {
191
- if (entry.parsed.kind === "structured") {
192
- return (
193
- <StructuredSuggestionRow
194
- key={entry.raw}
195
- suggestion={
196
- entry.parsed as Extract<
197
- ParsedSuggestion,
198
- { kind: "structured" }
199
- >
200
- }
201
- index={index}
202
- disabled={disabled}
203
- onSelect={() => onSelect(entry.raw)}
204
- />
205
- );
206
- }
207
-
208
- return (
209
- <CompactSuggestionRow
210
- key={entry.raw}
211
- text={entry.raw}
212
- index={index}
213
- disabled={disabled}
214
- custom={entry.parsed.kind === "custom"}
215
- onSelect={() => onSelect(entry.raw)}
216
- />
217
- );
218
- })}
219
- </div>
220
- <p className="assistant-reply-suggestions__hint">
221
- <kbd className="assistant-reply-kbd">1</kbd>
222
- <span aria-hidden>–</span>
223
- <kbd className="assistant-reply-kbd">
224
- {suggestions.suggestions.length}
225
- </kbd>
226
- <span>to pick · or type below</span>
227
- </p>
228
- </div>
229
- </fieldset>
230
- );
231
- }
@@ -1,69 +0,0 @@
1
- import { Terminal } from "lucide-react";
2
- import type { ChatCommandSuggestion } from "../../../core/chat-commands.ts";
3
- import { cn } from "../../utils/cn.ts";
4
-
5
- interface ComposerCommandMenuProps {
6
- commands: ChatCommandSuggestion[];
7
- selectedIndex: number;
8
- onSelect: (command: ChatCommandSuggestion) => void;
9
- className?: string;
10
- }
11
-
12
- export function ComposerCommandMenu({
13
- commands,
14
- selectedIndex,
15
- onSelect,
16
- className,
17
- }: ComposerCommandMenuProps) {
18
- if (commands.length === 0) {
19
- return null;
20
- }
21
-
22
- return (
23
- <div
24
- className={cn("composer-command-menu", className)}
25
- role="listbox"
26
- aria-label="Composer commands"
27
- >
28
- <div className="composer-command-menu__header">Commands</div>
29
- <ul className="composer-command-menu__list">
30
- {commands.map((command, index) => {
31
- const active = index === selectedIndex;
32
-
33
- return (
34
- <li key={command.name} role="presentation">
35
- <button
36
- type="button"
37
- role="option"
38
- aria-selected={active}
39
- className={cn(
40
- "composer-command-menu__item",
41
- active && "composer-command-menu__item--active",
42
- )}
43
- onMouseDown={(event) => {
44
- event.preventDefault();
45
- onSelect(command);
46
- }}
47
- >
48
- <Terminal
49
- className="composer-command-menu__icon"
50
- size={14}
51
- strokeWidth={2}
52
- aria-hidden
53
- />
54
- <span className="min-w-0">
55
- <span className="composer-command-menu__usage">
56
- {command.usage}
57
- </span>
58
- <span className="composer-command-menu__description">
59
- {command.description}
60
- </span>
61
- </span>
62
- </button>
63
- </li>
64
- );
65
- })}
66
- </ul>
67
- </div>
68
- );
69
- }