thepopebot 1.1.2 → 1.2.3

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 (143) hide show
  1. package/README.md +1 -1
  2. package/api/index.js +72 -165
  3. package/bin/cli.js +36 -6
  4. package/bin/local.sh +31 -0
  5. package/bin/postinstall.js +6 -2
  6. package/config/index.js +2 -11
  7. package/config/instrumentation.js +17 -5
  8. package/lib/actions.js +7 -6
  9. package/lib/ai/agent.js +36 -0
  10. package/lib/ai/index.js +274 -0
  11. package/lib/ai/model.js +67 -0
  12. package/lib/ai/tools.js +49 -0
  13. package/lib/auth/actions.js +28 -0
  14. package/lib/auth/config.js +45 -0
  15. package/lib/auth/index.js +27 -0
  16. package/lib/auth/middleware.js +30 -0
  17. package/lib/channels/base.js +56 -0
  18. package/lib/channels/index.js +15 -0
  19. package/lib/channels/telegram.js +146 -0
  20. package/lib/chat/actions.js +239 -0
  21. package/lib/chat/api.js +103 -0
  22. package/lib/chat/components/app-sidebar.js +161 -0
  23. package/lib/chat/components/app-sidebar.jsx +214 -0
  24. package/lib/chat/components/chat-header.js +9 -0
  25. package/lib/chat/components/chat-header.jsx +14 -0
  26. package/lib/chat/components/chat-input.js +230 -0
  27. package/lib/chat/components/chat-input.jsx +232 -0
  28. package/lib/chat/components/chat-nav-context.js +11 -0
  29. package/lib/chat/components/chat-nav-context.jsx +11 -0
  30. package/lib/chat/components/chat-page.js +70 -0
  31. package/lib/chat/components/chat-page.jsx +89 -0
  32. package/lib/chat/components/chat.js +78 -0
  33. package/lib/chat/components/chat.jsx +91 -0
  34. package/lib/chat/components/chats-page.js +170 -0
  35. package/lib/chat/components/chats-page.jsx +203 -0
  36. package/lib/chat/components/crons-page.js +144 -0
  37. package/lib/chat/components/crons-page.jsx +204 -0
  38. package/lib/chat/components/greeting.js +11 -0
  39. package/lib/chat/components/greeting.jsx +14 -0
  40. package/lib/chat/components/icons.js +518 -0
  41. package/lib/chat/components/icons.jsx +482 -0
  42. package/lib/chat/components/index.js +19 -0
  43. package/lib/chat/components/message.js +66 -0
  44. package/lib/chat/components/message.jsx +92 -0
  45. package/lib/chat/components/messages.js +63 -0
  46. package/lib/chat/components/messages.jsx +72 -0
  47. package/lib/chat/components/notifications-page.js +54 -0
  48. package/lib/chat/components/notifications-page.jsx +83 -0
  49. package/lib/chat/components/page-layout.js +21 -0
  50. package/lib/chat/components/page-layout.jsx +28 -0
  51. package/lib/chat/components/settings-layout.js +37 -0
  52. package/lib/chat/components/settings-layout.jsx +51 -0
  53. package/lib/chat/components/settings-secrets-page.js +216 -0
  54. package/lib/chat/components/settings-secrets-page.jsx +264 -0
  55. package/lib/chat/components/sidebar-history-item.js +54 -0
  56. package/lib/chat/components/sidebar-history-item.jsx +50 -0
  57. package/lib/chat/components/sidebar-history.js +92 -0
  58. package/lib/chat/components/sidebar-history.jsx +132 -0
  59. package/lib/chat/components/sidebar-user-nav.js +59 -0
  60. package/lib/chat/components/sidebar-user-nav.jsx +69 -0
  61. package/lib/chat/components/swarm-page.js +250 -0
  62. package/lib/chat/components/swarm-page.jsx +356 -0
  63. package/lib/chat/components/triggers-page.js +121 -0
  64. package/lib/chat/components/triggers-page.jsx +177 -0
  65. package/lib/chat/components/ui/dropdown-menu.js +98 -0
  66. package/lib/chat/components/ui/dropdown-menu.jsx +116 -0
  67. package/lib/chat/components/ui/scroll-area.js +13 -0
  68. package/lib/chat/components/ui/scroll-area.jsx +17 -0
  69. package/lib/chat/components/ui/separator.js +21 -0
  70. package/lib/chat/components/ui/separator.jsx +18 -0
  71. package/lib/chat/components/ui/sheet.js +75 -0
  72. package/lib/chat/components/ui/sheet.jsx +95 -0
  73. package/lib/chat/components/ui/sidebar.js +227 -0
  74. package/lib/chat/components/ui/sidebar.jsx +245 -0
  75. package/lib/chat/components/ui/tooltip.js +56 -0
  76. package/lib/chat/components/ui/tooltip.jsx +66 -0
  77. package/lib/chat/utils.js +11 -0
  78. package/lib/cron.js +7 -8
  79. package/lib/db/api-keys.js +160 -0
  80. package/lib/db/chats.js +129 -0
  81. package/lib/db/index.js +106 -0
  82. package/lib/db/notifications.js +99 -0
  83. package/lib/db/schema.js +51 -0
  84. package/lib/db/users.js +89 -0
  85. package/lib/paths.js +23 -17
  86. package/lib/tools/create-job.js +3 -3
  87. package/lib/tools/github.js +145 -1
  88. package/lib/tools/openai.js +1 -1
  89. package/lib/tools/telegram.js +4 -3
  90. package/lib/triggers.js +6 -7
  91. package/lib/utils/render-md.js +6 -6
  92. package/package.json +43 -6
  93. package/setup/lib/auth.mjs +22 -9
  94. package/setup/lib/prerequisites.mjs +10 -3
  95. package/setup/lib/telegram-verify.mjs +3 -16
  96. package/setup/setup-telegram.mjs +31 -62
  97. package/setup/setup.mjs +58 -98
  98. package/templates/.dockerignore +5 -0
  99. package/templates/.env.example +18 -2
  100. package/templates/.github/workflows/auto-merge.yml +1 -1
  101. package/templates/.github/workflows/build-image.yml +6 -4
  102. package/templates/.github/workflows/notify-job-failed.yml +2 -2
  103. package/templates/.github/workflows/notify-pr-complete.yml +2 -2
  104. package/templates/.github/workflows/run-job.yml +24 -10
  105. package/templates/CLAUDE.md +5 -3
  106. package/templates/app/api/auth/[...nextauth]/route.js +1 -0
  107. package/templates/app/api/chat/route.js +1 -0
  108. package/templates/app/chat/[chatId]/page.js +8 -0
  109. package/templates/app/chats/page.js +7 -0
  110. package/templates/app/components/ascii-logo.jsx +10 -0
  111. package/templates/app/components/login-form.jsx +81 -0
  112. package/templates/app/components/setup-form.jsx +82 -0
  113. package/templates/app/components/theme-provider.jsx +11 -0
  114. package/templates/app/components/theme-toggle.jsx +38 -0
  115. package/templates/app/components/ui/button.jsx +21 -0
  116. package/templates/app/components/ui/card.jsx +23 -0
  117. package/templates/app/components/ui/input.jsx +10 -0
  118. package/templates/app/components/ui/label.jsx +10 -0
  119. package/templates/app/crons/page.js +7 -0
  120. package/templates/app/globals.css +66 -0
  121. package/templates/app/layout.js +9 -2
  122. package/templates/app/login/page.js +15 -0
  123. package/templates/app/notifications/page.js +7 -0
  124. package/templates/app/page.js +6 -30
  125. package/templates/app/settings/layout.js +7 -0
  126. package/templates/app/settings/page.js +5 -0
  127. package/templates/app/settings/secrets/page.js +5 -0
  128. package/templates/app/swarm/page.js +7 -0
  129. package/templates/app/triggers/page.js +7 -0
  130. package/templates/config/CRONS.json +2 -2
  131. package/templates/config/TRIGGERS.json +2 -2
  132. package/templates/docker/event_handler/Dockerfile +19 -0
  133. package/templates/docker/{entrypoint.sh → job/entrypoint.sh} +4 -4
  134. package/templates/docker/runner/Dockerfile +38 -0
  135. package/templates/docker/runner/entrypoint.sh +41 -0
  136. package/templates/docker-compose.yml +52 -0
  137. package/templates/instrumentation.js +6 -1
  138. package/templates/middleware.js +1 -0
  139. package/templates/postcss.config.mjs +5 -0
  140. package/lib/claude/conversation.js +0 -76
  141. package/lib/claude/index.js +0 -142
  142. package/lib/claude/tools.js +0 -54
  143. /package/templates/docker/{Dockerfile → job/Dockerfile} +0 -0
@@ -0,0 +1,214 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { SquarePenIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon, ClockIcon, ZapIcon } from './icons.js';
5
+ import { getUnreadNotificationCount } from '../actions.js';
6
+ import { SidebarHistory } from './sidebar-history.js';
7
+ import { SidebarUserNav } from './sidebar-user-nav.js';
8
+ import {
9
+ Sidebar,
10
+ SidebarContent,
11
+ SidebarFooter,
12
+ SidebarHeader,
13
+ SidebarGroup,
14
+ SidebarGroupLabel,
15
+ SidebarMenu,
16
+ SidebarMenuItem,
17
+ SidebarMenuButton,
18
+ useSidebar,
19
+ } from './ui/sidebar.js';
20
+ import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip.js';
21
+ import { useChatNav } from './chat-nav-context.js';
22
+
23
+ export function AppSidebar({ user }) {
24
+ const { navigateToChat } = useChatNav();
25
+ const { state, open, setOpenMobile, toggleSidebar } = useSidebar();
26
+ const collapsed = state === 'collapsed';
27
+ const [unreadCount, setUnreadCount] = useState(0);
28
+
29
+ useEffect(() => {
30
+ getUnreadNotificationCount()
31
+ .then((count) => setUnreadCount(count))
32
+ .catch(() => {});
33
+ }, []);
34
+
35
+ return (
36
+ <Sidebar>
37
+ <SidebarHeader>
38
+ {/* Top row: brand name + toggle icon (open) or just toggle icon (collapsed) */}
39
+ <div className={collapsed ? 'flex justify-center' : 'flex items-center justify-between'}>
40
+ {!collapsed && (
41
+ <span className="px-2 font-semibold text-lg">The Pope Bot</span>
42
+ )}
43
+ <Tooltip>
44
+ <TooltipTrigger asChild>
45
+ <button
46
+ className="inline-flex shrink-0 items-center justify-center rounded-md p-2 text-muted-foreground hover:bg-background hover:text-foreground"
47
+ onClick={toggleSidebar}
48
+ >
49
+ <PanelLeftIcon size={16} />
50
+ </button>
51
+ </TooltipTrigger>
52
+ <TooltipContent side={collapsed ? 'right' : 'bottom'}>
53
+ {collapsed ? 'Open sidebar' : 'Close sidebar'}
54
+ </TooltipContent>
55
+ </Tooltip>
56
+ </div>
57
+
58
+ <SidebarMenu>
59
+ {/* New chat */}
60
+ <SidebarMenuItem>
61
+ <Tooltip>
62
+ <TooltipTrigger asChild>
63
+ <SidebarMenuButton
64
+ className={collapsed ? 'justify-center' : ''}
65
+ onClick={() => {
66
+ navigateToChat(null);
67
+ setOpenMobile(false);
68
+ }}
69
+ >
70
+ <SquarePenIcon size={16} />
71
+ {!collapsed && <span>New chat</span>}
72
+ </SidebarMenuButton>
73
+ </TooltipTrigger>
74
+ {collapsed && (
75
+ <TooltipContent side="right">New chat</TooltipContent>
76
+ )}
77
+ </Tooltip>
78
+ </SidebarMenuItem>
79
+
80
+ {/* Chats history */}
81
+ <SidebarMenuItem>
82
+ <Tooltip>
83
+ <TooltipTrigger asChild>
84
+ <SidebarMenuButton
85
+ className={collapsed ? 'justify-center' : ''}
86
+ onClick={() => {
87
+ window.location.href = '/chats';
88
+ }}
89
+ >
90
+ <MessageIcon size={16} />
91
+ {!collapsed && <span>Chats</span>}
92
+ </SidebarMenuButton>
93
+ </TooltipTrigger>
94
+ {collapsed && (
95
+ <TooltipContent side="right">Chats</TooltipContent>
96
+ )}
97
+ </Tooltip>
98
+ </SidebarMenuItem>
99
+
100
+ {/* Notifications */}
101
+ <SidebarMenuItem>
102
+ <Tooltip>
103
+ <TooltipTrigger asChild>
104
+ <SidebarMenuButton
105
+ className={collapsed ? 'justify-center' : ''}
106
+ onClick={() => {
107
+ window.location.href = '/notifications';
108
+ }}
109
+ >
110
+ <BellIcon size={16} />
111
+ {!collapsed && (
112
+ <span className="flex items-center gap-2">
113
+ Notifications
114
+ {unreadCount > 0 && (
115
+ <span className="inline-flex items-center justify-center rounded-full bg-destructive px-1.5 py-0.5 text-[10px] font-medium leading-none text-destructive-foreground">
116
+ {unreadCount}
117
+ </span>
118
+ )}
119
+ </span>
120
+ )}
121
+ {collapsed && unreadCount > 0 && (
122
+ <span className="absolute -top-1 -right-1 inline-flex h-4 w-4 items-center justify-center rounded-full bg-destructive text-[10px] font-medium text-destructive-foreground">
123
+ {unreadCount}
124
+ </span>
125
+ )}
126
+ </SidebarMenuButton>
127
+ </TooltipTrigger>
128
+ {collapsed && (
129
+ <TooltipContent side="right">Notifications</TooltipContent>
130
+ )}
131
+ </Tooltip>
132
+ </SidebarMenuItem>
133
+
134
+ {/* Swarm */}
135
+ <SidebarMenuItem>
136
+ <Tooltip>
137
+ <TooltipTrigger asChild>
138
+ <SidebarMenuButton
139
+ className={collapsed ? 'justify-center' : ''}
140
+ onClick={() => {
141
+ window.location.href = '/swarm';
142
+ }}
143
+ >
144
+ <SwarmIcon size={16} />
145
+ {!collapsed && <span>Swarm</span>}
146
+ </SidebarMenuButton>
147
+ </TooltipTrigger>
148
+ {collapsed && (
149
+ <TooltipContent side="right">Swarm</TooltipContent>
150
+ )}
151
+ </Tooltip>
152
+ </SidebarMenuItem>
153
+
154
+ {/* Cron Jobs */}
155
+ <SidebarMenuItem>
156
+ <Tooltip>
157
+ <TooltipTrigger asChild>
158
+ <SidebarMenuButton
159
+ className={collapsed ? 'justify-center' : ''}
160
+ onClick={() => {
161
+ window.location.href = '/crons';
162
+ }}
163
+ >
164
+ <ClockIcon size={16} />
165
+ {!collapsed && <span>Cron Jobs</span>}
166
+ </SidebarMenuButton>
167
+ </TooltipTrigger>
168
+ {collapsed && (
169
+ <TooltipContent side="right">Cron Jobs</TooltipContent>
170
+ )}
171
+ </Tooltip>
172
+ </SidebarMenuItem>
173
+
174
+ {/* Triggers */}
175
+ <SidebarMenuItem>
176
+ <Tooltip>
177
+ <TooltipTrigger asChild>
178
+ <SidebarMenuButton
179
+ className={collapsed ? 'justify-center' : ''}
180
+ onClick={() => {
181
+ window.location.href = '/triggers';
182
+ }}
183
+ >
184
+ <ZapIcon size={16} />
185
+ {!collapsed && <span>Triggers</span>}
186
+ </SidebarMenuButton>
187
+ </TooltipTrigger>
188
+ {collapsed && (
189
+ <TooltipContent side="right">Triggers</TooltipContent>
190
+ )}
191
+ </Tooltip>
192
+ </SidebarMenuItem>
193
+
194
+ </SidebarMenu>
195
+ </SidebarHeader>
196
+
197
+ {!collapsed && (
198
+ <SidebarContent>
199
+ <SidebarGroup className="pt-0">
200
+ <SidebarGroupLabel>Chats</SidebarGroupLabel>
201
+ </SidebarGroup>
202
+ <SidebarHistory />
203
+ </SidebarContent>
204
+ )}
205
+
206
+ {/* Spacer when collapsed to push footer down */}
207
+ {collapsed && <div className="flex-1" />}
208
+
209
+ <SidebarFooter>
210
+ {user && <SidebarUserNav user={user} collapsed={collapsed} />}
211
+ </SidebarFooter>
212
+ </Sidebar>
213
+ );
214
+ }
@@ -0,0 +1,9 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { SidebarTrigger } from "./ui/sidebar.js";
4
+ function ChatHeader({ chatId }) {
5
+ return /* @__PURE__ */ jsx("header", { className: "sticky top-0 flex items-center gap-2 bg-background px-2 py-1.5 md:px-2 z-10", children: /* @__PURE__ */ jsx("div", { className: "md:hidden", children: /* @__PURE__ */ jsx(SidebarTrigger, {}) }) });
6
+ }
7
+ export {
8
+ ChatHeader
9
+ };
@@ -0,0 +1,14 @@
1
+ 'use client';
2
+
3
+ import { SidebarTrigger } from './ui/sidebar.js';
4
+
5
+ export function ChatHeader({ chatId }) {
6
+ return (
7
+ <header className="sticky top-0 flex items-center gap-2 bg-background px-2 py-1.5 md:px-2 z-10">
8
+ {/* Mobile-only: open sidebar sheet */}
9
+ <div className="md:hidden">
10
+ <SidebarTrigger />
11
+ </div>
12
+ </header>
13
+ );
14
+ }
@@ -0,0 +1,230 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useRef, useEffect, useCallback, useState } from "react";
4
+ import { SendIcon, StopIcon, PaperclipIcon, XIcon, FileTextIcon } from "./icons.js";
5
+ import { cn } from "../utils.js";
6
+ const ACCEPTED_TYPES = [
7
+ "image/jpeg",
8
+ "image/png",
9
+ "image/gif",
10
+ "image/webp",
11
+ "application/pdf",
12
+ "text/plain",
13
+ "text/markdown",
14
+ "text/csv",
15
+ "text/html",
16
+ "text/css",
17
+ "text/javascript",
18
+ "text/x-python",
19
+ "text/x-typescript",
20
+ "application/json"
21
+ ];
22
+ const MAX_FILES = 5;
23
+ function isAcceptedType(file) {
24
+ if (ACCEPTED_TYPES.includes(file.type)) return true;
25
+ const ext = file.name?.split(".").pop()?.toLowerCase();
26
+ const textExts = ["txt", "md", "csv", "json", "js", "ts", "jsx", "tsx", "py", "html", "css", "yml", "yaml", "xml", "sh", "bash", "rb", "go", "rs", "java", "c", "cpp", "h", "hpp"];
27
+ return textExts.includes(ext);
28
+ }
29
+ function getEffectiveType(file) {
30
+ if (ACCEPTED_TYPES.includes(file.type) && file.type !== "") return file.type;
31
+ const ext = file.name?.split(".").pop()?.toLowerCase();
32
+ const extMap = {
33
+ txt: "text/plain",
34
+ md: "text/markdown",
35
+ csv: "text/csv",
36
+ json: "application/json",
37
+ js: "text/javascript",
38
+ ts: "text/x-typescript",
39
+ jsx: "text/javascript",
40
+ tsx: "text/x-typescript",
41
+ py: "text/x-python",
42
+ html: "text/html",
43
+ css: "text/css",
44
+ yml: "text/plain",
45
+ yaml: "text/plain",
46
+ xml: "text/plain",
47
+ sh: "text/plain",
48
+ bash: "text/plain",
49
+ rb: "text/plain",
50
+ go: "text/plain",
51
+ rs: "text/plain",
52
+ java: "text/plain",
53
+ c: "text/plain",
54
+ cpp: "text/plain",
55
+ h: "text/plain",
56
+ hpp: "text/plain"
57
+ };
58
+ return extMap[ext] || file.type || "text/plain";
59
+ }
60
+ function ChatInput({ input, setInput, onSubmit, status, stop, files, setFiles }) {
61
+ const textareaRef = useRef(null);
62
+ const fileInputRef = useRef(null);
63
+ const [isDragging, setIsDragging] = useState(false);
64
+ const isStreaming = status === "streaming" || status === "submitted";
65
+ const adjustHeight = useCallback(() => {
66
+ const textarea = textareaRef.current;
67
+ if (!textarea) return;
68
+ textarea.style.height = "auto";
69
+ textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
70
+ }, []);
71
+ useEffect(() => {
72
+ adjustHeight();
73
+ }, [input, adjustHeight]);
74
+ useEffect(() => {
75
+ textareaRef.current?.focus();
76
+ }, []);
77
+ const handleFiles = useCallback((fileList) => {
78
+ const newFiles = Array.from(fileList).filter(isAcceptedType);
79
+ if (newFiles.length === 0) return;
80
+ newFiles.forEach((file) => {
81
+ const reader = new FileReader();
82
+ reader.onload = () => {
83
+ setFiles((current) => {
84
+ if (current.length >= MAX_FILES) return current;
85
+ return [...current, { file, previewUrl: reader.result }];
86
+ });
87
+ };
88
+ reader.readAsDataURL(file);
89
+ });
90
+ }, [setFiles]);
91
+ const removeFile = (index) => {
92
+ setFiles((prev) => prev.filter((_, i) => i !== index));
93
+ };
94
+ const handleSubmit = (e) => {
95
+ if (e) e.preventDefault();
96
+ if (!input.trim() && files.length === 0 || isStreaming) return;
97
+ onSubmit();
98
+ };
99
+ const handleKeyDown = (e) => {
100
+ if (e.key === "Enter" && !e.shiftKey) {
101
+ e.preventDefault();
102
+ handleSubmit();
103
+ }
104
+ };
105
+ const handleDragOver = (e) => {
106
+ e.preventDefault();
107
+ setIsDragging(true);
108
+ };
109
+ const handleDragLeave = (e) => {
110
+ e.preventDefault();
111
+ setIsDragging(false);
112
+ };
113
+ const handleDrop = (e) => {
114
+ e.preventDefault();
115
+ setIsDragging(false);
116
+ if (e.dataTransfer?.files?.length) {
117
+ handleFiles(e.dataTransfer.files);
118
+ }
119
+ };
120
+ const canSend = input.trim() || files.length > 0;
121
+ return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-4xl px-2 pb-4 md:px-4", children: /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, className: "relative", children: /* @__PURE__ */ jsxs(
122
+ "div",
123
+ {
124
+ className: cn(
125
+ "flex flex-col rounded-xl border bg-muted p-2 transition-colors",
126
+ isDragging ? "border-primary bg-primary/5" : "border-border"
127
+ ),
128
+ onDragOver: handleDragOver,
129
+ onDragLeave: handleDragLeave,
130
+ onDrop: handleDrop,
131
+ children: [
132
+ files.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-2 flex gap-2 overflow-x-auto px-1 py-1", children: files.map((f, i) => {
133
+ const isImage = f.file.type.startsWith("image/");
134
+ return /* @__PURE__ */ jsxs("div", { className: "group relative flex-shrink-0", children: [
135
+ isImage ? /* @__PURE__ */ jsx(
136
+ "img",
137
+ {
138
+ src: f.previewUrl,
139
+ alt: f.file.name,
140
+ className: "h-16 w-16 rounded-lg object-cover"
141
+ }
142
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex h-16 items-center gap-1.5 rounded-lg bg-foreground/10 px-3", children: [
143
+ /* @__PURE__ */ jsx(FileTextIcon, { size: 14 }),
144
+ /* @__PURE__ */ jsx("span", { className: "max-w-[100px] truncate text-xs", children: f.file.name })
145
+ ] }),
146
+ /* @__PURE__ */ jsx(
147
+ "button",
148
+ {
149
+ type: "button",
150
+ onClick: () => removeFile(i),
151
+ className: "absolute -right-1.5 -top-1.5 hidden rounded-full bg-foreground p-0.5 text-background group-hover:flex items-center justify-center",
152
+ "aria-label": `Remove ${f.file.name}`,
153
+ children: /* @__PURE__ */ jsx(XIcon, { size: 10 })
154
+ }
155
+ )
156
+ ] }, i);
157
+ }) }),
158
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
159
+ /* @__PURE__ */ jsx(
160
+ "button",
161
+ {
162
+ type: "button",
163
+ onClick: () => fileInputRef.current?.click(),
164
+ className: "inline-flex items-center justify-center rounded-lg p-2 text-muted-foreground hover:text-foreground",
165
+ "aria-label": "Attach files",
166
+ disabled: isStreaming,
167
+ children: /* @__PURE__ */ jsx(PaperclipIcon, { size: 16 })
168
+ }
169
+ ),
170
+ /* @__PURE__ */ jsx(
171
+ "input",
172
+ {
173
+ ref: fileInputRef,
174
+ type: "file",
175
+ multiple: true,
176
+ accept: "image/*,application/pdf,text/*,application/json,.md,.csv,.json,.js,.ts,.jsx,.tsx,.py,.html,.css,.yml,.yaml,.xml,.sh,.rb,.go,.rs,.java,.c,.cpp,.h",
177
+ className: "hidden",
178
+ onChange: (e) => {
179
+ if (e.target.files?.length) handleFiles(e.target.files);
180
+ e.target.value = "";
181
+ }
182
+ }
183
+ ),
184
+ /* @__PURE__ */ jsx(
185
+ "textarea",
186
+ {
187
+ ref: textareaRef,
188
+ value: input,
189
+ onChange: (e) => setInput(e.target.value),
190
+ onKeyDown: handleKeyDown,
191
+ placeholder: "Send a message...",
192
+ rows: 1,
193
+ className: cn(
194
+ "flex-1 resize-none bg-transparent px-2 py-1.5 text-sm text-foreground",
195
+ "placeholder:text-muted-foreground focus:outline-none",
196
+ "max-h-[200px]"
197
+ ),
198
+ disabled: isStreaming
199
+ }
200
+ ),
201
+ isStreaming ? /* @__PURE__ */ jsx(
202
+ "button",
203
+ {
204
+ type: "button",
205
+ onClick: stop,
206
+ className: "inline-flex items-center justify-center rounded-lg bg-foreground p-2 text-background hover:opacity-80",
207
+ "aria-label": "Stop generating",
208
+ children: /* @__PURE__ */ jsx(StopIcon, { size: 16 })
209
+ }
210
+ ) : /* @__PURE__ */ jsx(
211
+ "button",
212
+ {
213
+ type: "submit",
214
+ disabled: !canSend,
215
+ className: cn(
216
+ "inline-flex items-center justify-center rounded-lg p-2",
217
+ canSend ? "bg-foreground text-background hover:opacity-80" : "bg-muted-foreground/20 text-muted-foreground cursor-not-allowed"
218
+ ),
219
+ "aria-label": "Send message",
220
+ children: /* @__PURE__ */ jsx(SendIcon, { size: 16 })
221
+ }
222
+ )
223
+ ] })
224
+ ]
225
+ }
226
+ ) }) });
227
+ }
228
+ export {
229
+ ChatInput
230
+ };