@harbinger-ai/harbinger 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 (317) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +406 -0
  3. package/agents/README.md +76 -0
  4. package/agents/_template/CONFIG.yaml +7 -0
  5. package/agents/_template/HEARTBEAT.md +59 -0
  6. package/agents/_template/IDENTITY.md +4 -0
  7. package/agents/_template/SKILLS.md +1 -0
  8. package/agents/_template/SOUL.md +25 -0
  9. package/agents/_template/TOOLS.md +3 -0
  10. package/agents/binary-reverser/CONFIG.yaml +21 -0
  11. package/agents/binary-reverser/HEARTBEAT.md +65 -0
  12. package/agents/binary-reverser/IDENTITY.md +1 -0
  13. package/agents/binary-reverser/SKILLS.md +1 -0
  14. package/agents/binary-reverser/SOUL.md +23 -0
  15. package/agents/binary-reverser/TOOLS.md +99 -0
  16. package/agents/browser-agent/CONFIG.yaml +20 -0
  17. package/agents/browser-agent/HEARTBEAT.md +79 -0
  18. package/agents/browser-agent/IDENTITY.md +5 -0
  19. package/agents/browser-agent/SKILLS.md +86 -0
  20. package/agents/browser-agent/SOUL.md +23 -0
  21. package/agents/browser-agent/TOOLS.md +186 -0
  22. package/agents/cloud-infiltrator/CONFIG.yaml +22 -0
  23. package/agents/cloud-infiltrator/HEARTBEAT.md +78 -0
  24. package/agents/cloud-infiltrator/IDENTITY.md +1 -0
  25. package/agents/cloud-infiltrator/SKILLS.md +1 -0
  26. package/agents/cloud-infiltrator/SOUL.md +23 -0
  27. package/agents/cloud-infiltrator/TOOLS.md +68 -0
  28. package/agents/coding-assistant/CONFIG.yaml +22 -0
  29. package/agents/coding-assistant/HEARTBEAT.md +57 -0
  30. package/agents/coding-assistant/IDENTITY.md +5 -0
  31. package/agents/coding-assistant/SKILLS.md +69 -0
  32. package/agents/coding-assistant/SOUL.md +60 -0
  33. package/agents/coding-assistant/TOOLS.md +168 -0
  34. package/agents/learning-agent/CONFIG.yaml +21 -0
  35. package/agents/learning-agent/HEARTBEAT.md +63 -0
  36. package/agents/learning-agent/IDENTITY.md +5 -0
  37. package/agents/learning-agent/SKILLS.md +86 -0
  38. package/agents/learning-agent/SOUL.md +77 -0
  39. package/agents/learning-agent/TOOLS.md +145 -0
  40. package/agents/maintainer/CONFIG.yaml +31 -0
  41. package/agents/maintainer/HEARTBEAT.md +28 -0
  42. package/agents/maintainer/IDENTITY.md +33 -0
  43. package/agents/maintainer/SKILLS.md +24 -0
  44. package/agents/maintainer/SOUL.md +61 -0
  45. package/agents/maintainer/TOOLS.md +29 -0
  46. package/agents/maintainer/lib/engine.js +279 -0
  47. package/agents/maintainer/lib/safe-fixer.js +183 -0
  48. package/agents/morning-brief/CONFIG.yaml +22 -0
  49. package/agents/morning-brief/HEARTBEAT.md +60 -0
  50. package/agents/morning-brief/IDENTITY.md +5 -0
  51. package/agents/morning-brief/SKILLS.md +56 -0
  52. package/agents/morning-brief/SOUL.md +64 -0
  53. package/agents/morning-brief/TOOLS.md +112 -0
  54. package/agents/osint-detective/CONFIG.yaml +24 -0
  55. package/agents/osint-detective/HEARTBEAT.md +66 -0
  56. package/agents/osint-detective/IDENTITY.md +1 -0
  57. package/agents/osint-detective/SKILLS.md +1 -0
  58. package/agents/osint-detective/SOUL.md +23 -0
  59. package/agents/osint-detective/TOOLS.md +81 -0
  60. package/agents/recon-scout/CONFIG.yaml +22 -0
  61. package/agents/recon-scout/HEARTBEAT.md +79 -0
  62. package/agents/recon-scout/IDENTITY.md +1 -0
  63. package/agents/recon-scout/SKILLS.md +1 -0
  64. package/agents/recon-scout/SOUL.md +23 -0
  65. package/agents/recon-scout/TOOLS.md +93 -0
  66. package/agents/report-writer/CONFIG.yaml +21 -0
  67. package/agents/report-writer/HEARTBEAT.md +63 -0
  68. package/agents/report-writer/IDENTITY.md +1 -0
  69. package/agents/report-writer/SKILLS.md +1 -0
  70. package/agents/report-writer/SOUL.md +23 -0
  71. package/agents/report-writer/TOOLS.md +69 -0
  72. package/agents/shared/README.md +13 -0
  73. package/agents/web-hacker/CONFIG.yaml +24 -0
  74. package/agents/web-hacker/HEARTBEAT.md +78 -0
  75. package/agents/web-hacker/IDENTITY.md +1 -0
  76. package/agents/web-hacker/SKILLS.md +1 -0
  77. package/agents/web-hacker/SOUL.md +23 -0
  78. package/agents/web-hacker/TOOLS.md +86 -0
  79. package/api/CLAUDE.md +19 -0
  80. package/api/index.js +274 -0
  81. package/bin/cli.js +620 -0
  82. package/bin/local.sh +31 -0
  83. package/bin/postinstall.js +63 -0
  84. package/config/index.js +24 -0
  85. package/config/instrumentation.js +93 -0
  86. package/drizzle/0000_initial.sql +52 -0
  87. package/drizzle/0001_bounty_and_registry.sql +82 -0
  88. package/drizzle/0002_sync_columns.sql +7 -0
  89. package/drizzle/0003_graceful_bloodscream.sql +86 -0
  90. package/drizzle/meta/0000_snapshot.json +321 -0
  91. package/drizzle/meta/0003_snapshot.json +878 -0
  92. package/drizzle/meta/_journal.json +34 -0
  93. package/drizzle/relations.ts +3 -0
  94. package/drizzle/schema.ts +145 -0
  95. package/lib/actions.js +47 -0
  96. package/lib/agents.js +166 -0
  97. package/lib/ai/agent.js +96 -0
  98. package/lib/ai/autonomous-engine.js +261 -0
  99. package/lib/ai/index.js +359 -0
  100. package/lib/ai/model-router.js +254 -0
  101. package/lib/ai/model.js +73 -0
  102. package/lib/ai/tools.js +84 -0
  103. package/lib/auth/actions.js +28 -0
  104. package/lib/auth/config.js +27 -0
  105. package/lib/auth/edge-config.js +27 -0
  106. package/lib/auth/index.js +27 -0
  107. package/lib/auth/middleware.js +53 -0
  108. package/lib/bounty/actions.js +119 -0
  109. package/lib/bounty/findings.js +64 -0
  110. package/lib/bounty/programs.js +34 -0
  111. package/lib/bounty/sync-targets.js +267 -0
  112. package/lib/bounty/targets.js +33 -0
  113. package/lib/channels/base.js +56 -0
  114. package/lib/channels/index.js +15 -0
  115. package/lib/channels/telegram.js +148 -0
  116. package/lib/chat/actions.js +288 -0
  117. package/lib/chat/api.js +135 -0
  118. package/lib/chat/components/app-sidebar.js +237 -0
  119. package/lib/chat/components/app-sidebar.jsx +289 -0
  120. package/lib/chat/components/chat-header.js +27 -0
  121. package/lib/chat/components/chat-header.jsx +37 -0
  122. package/lib/chat/components/chat-input.js +230 -0
  123. package/lib/chat/components/chat-input.jsx +228 -0
  124. package/lib/chat/components/chat-nav-context.js +11 -0
  125. package/lib/chat/components/chat-nav-context.jsx +11 -0
  126. package/lib/chat/components/chat-page.js +81 -0
  127. package/lib/chat/components/chat-page.jsx +100 -0
  128. package/lib/chat/components/chat.js +150 -0
  129. package/lib/chat/components/chat.jsx +182 -0
  130. package/lib/chat/components/chats-page.js +302 -0
  131. package/lib/chat/components/chats-page.jsx +330 -0
  132. package/lib/chat/components/crons-page.js +172 -0
  133. package/lib/chat/components/crons-page.jsx +244 -0
  134. package/lib/chat/components/enhanced-tool-call.js +103 -0
  135. package/lib/chat/components/enhanced-tool-call.jsx +139 -0
  136. package/lib/chat/components/findings-page.js +175 -0
  137. package/lib/chat/components/findings-page.jsx +214 -0
  138. package/lib/chat/components/greeting.js +22 -0
  139. package/lib/chat/components/greeting.jsx +26 -0
  140. package/lib/chat/components/icons.js +777 -0
  141. package/lib/chat/components/icons.jsx +741 -0
  142. package/lib/chat/components/index.js +26 -0
  143. package/lib/chat/components/mcp-page.js +260 -0
  144. package/lib/chat/components/mcp-page.jsx +355 -0
  145. package/lib/chat/components/message.js +289 -0
  146. package/lib/chat/components/message.jsx +315 -0
  147. package/lib/chat/components/messages.js +66 -0
  148. package/lib/chat/components/messages.jsx +77 -0
  149. package/lib/chat/components/notifications-page.js +56 -0
  150. package/lib/chat/components/notifications-page.jsx +87 -0
  151. package/lib/chat/components/page-layout.js +21 -0
  152. package/lib/chat/components/page-layout.jsx +28 -0
  153. package/lib/chat/components/registry-page.js +222 -0
  154. package/lib/chat/components/registry-page.jsx +255 -0
  155. package/lib/chat/components/settings-layout.js +40 -0
  156. package/lib/chat/components/settings-layout.jsx +54 -0
  157. package/lib/chat/components/settings-secrets-page.js +216 -0
  158. package/lib/chat/components/settings-secrets-page.jsx +264 -0
  159. package/lib/chat/components/sidebar-history-item.js +132 -0
  160. package/lib/chat/components/sidebar-history-item.jsx +113 -0
  161. package/lib/chat/components/sidebar-history.js +115 -0
  162. package/lib/chat/components/sidebar-history.jsx +157 -0
  163. package/lib/chat/components/sidebar-user-nav.js +63 -0
  164. package/lib/chat/components/sidebar-user-nav.jsx +73 -0
  165. package/lib/chat/components/status-bar.js +39 -0
  166. package/lib/chat/components/status-bar.jsx +51 -0
  167. package/lib/chat/components/swarm-page.js +157 -0
  168. package/lib/chat/components/swarm-page.jsx +210 -0
  169. package/lib/chat/components/targets-page.js +376 -0
  170. package/lib/chat/components/targets-page.jsx +389 -0
  171. package/lib/chat/components/tool-call.js +86 -0
  172. package/lib/chat/components/tool-call.jsx +104 -0
  173. package/lib/chat/components/tool-panel.js +107 -0
  174. package/lib/chat/components/tool-panel.jsx +145 -0
  175. package/lib/chat/components/triggers-page.js +153 -0
  176. package/lib/chat/components/triggers-page.jsx +221 -0
  177. package/lib/chat/components/ui/confirm-dialog.js +53 -0
  178. package/lib/chat/components/ui/confirm-dialog.jsx +57 -0
  179. package/lib/chat/components/ui/dropdown-menu.js +98 -0
  180. package/lib/chat/components/ui/dropdown-menu.jsx +116 -0
  181. package/lib/chat/components/ui/rename-dialog.js +74 -0
  182. package/lib/chat/components/ui/rename-dialog.jsx +72 -0
  183. package/lib/chat/components/ui/scroll-area.js +13 -0
  184. package/lib/chat/components/ui/scroll-area.jsx +17 -0
  185. package/lib/chat/components/ui/separator.js +21 -0
  186. package/lib/chat/components/ui/separator.jsx +18 -0
  187. package/lib/chat/components/ui/sheet.js +75 -0
  188. package/lib/chat/components/ui/sheet.jsx +95 -0
  189. package/lib/chat/components/ui/sidebar.js +227 -0
  190. package/lib/chat/components/ui/sidebar.jsx +245 -0
  191. package/lib/chat/components/ui/tooltip.js +56 -0
  192. package/lib/chat/components/ui/tooltip.jsx +66 -0
  193. package/lib/chat/components/upgrade-dialog.js +151 -0
  194. package/lib/chat/components/upgrade-dialog.jsx +170 -0
  195. package/lib/chat/utils.js +11 -0
  196. package/lib/cron.js +246 -0
  197. package/lib/db/api-keys.js +163 -0
  198. package/lib/db/chats.js +145 -0
  199. package/lib/db/index.js +52 -0
  200. package/lib/db/notifications.js +99 -0
  201. package/lib/db/schema.js +145 -0
  202. package/lib/db/update-check.js +96 -0
  203. package/lib/db/users.js +89 -0
  204. package/lib/mcp/actions.js +104 -0
  205. package/lib/mcp/client.js +79 -0
  206. package/lib/mcp/handler.js +57 -0
  207. package/lib/mcp/server.js +165 -0
  208. package/lib/paths.js +46 -0
  209. package/lib/registry/actions.js +164 -0
  210. package/lib/registry/catalog.js +137 -0
  211. package/lib/registry/tools.js +71 -0
  212. package/lib/tools/create-job.js +99 -0
  213. package/lib/tools/github.js +217 -0
  214. package/lib/tools/openai.js +35 -0
  215. package/lib/tools/telegram.js +292 -0
  216. package/lib/triggers.js +118 -0
  217. package/lib/utils/render-md.js +102 -0
  218. package/package.json +103 -0
  219. package/setup/lib/auth.mjs +81 -0
  220. package/setup/lib/env.mjs +21 -0
  221. package/setup/lib/fs-utils.mjs +20 -0
  222. package/setup/lib/github.mjs +149 -0
  223. package/setup/lib/prerequisites.mjs +155 -0
  224. package/setup/lib/prompts.mjs +267 -0
  225. package/setup/lib/providers.mjs +48 -0
  226. package/setup/lib/sync.mjs +125 -0
  227. package/setup/lib/targets.mjs +45 -0
  228. package/setup/lib/telegram-verify.mjs +63 -0
  229. package/setup/lib/telegram.mjs +76 -0
  230. package/setup/setup-telegram.mjs +264 -0
  231. package/setup/setup.mjs +842 -0
  232. package/templates/.dockerignore +5 -0
  233. package/templates/.env.example +63 -0
  234. package/templates/.github/workflows/auto-merge.yml +117 -0
  235. package/templates/.github/workflows/build-image.yml +36 -0
  236. package/templates/.github/workflows/notify-job-failed.yml +64 -0
  237. package/templates/.github/workflows/notify-pr-complete.yml +119 -0
  238. package/templates/.github/workflows/rebuild-event-handler.yml +121 -0
  239. package/templates/.github/workflows/run-job.yml +89 -0
  240. package/templates/.github/workflows/upgrade-event-handler.yml +62 -0
  241. package/templates/.gitignore.template +45 -0
  242. package/templates/.pi/extensions/env-sanitizer/index.ts +48 -0
  243. package/templates/.pi/extensions/env-sanitizer/package.json +5 -0
  244. package/templates/CLAUDE.md +29 -0
  245. package/templates/CLAUDE.md.template +307 -0
  246. package/templates/app/api/[...thepopebot]/route.js +1 -0
  247. package/templates/app/api/auth/[...nextauth]/route.js +1 -0
  248. package/templates/app/chat/[chatId]/page.js +8 -0
  249. package/templates/app/chats/page.js +7 -0
  250. package/templates/app/components/ascii-logo.jsx +10 -0
  251. package/templates/app/components/login-form.jsx +92 -0
  252. package/templates/app/components/setup-form.jsx +82 -0
  253. package/templates/app/components/theme-provider.jsx +11 -0
  254. package/templates/app/components/theme-toggle.jsx +38 -0
  255. package/templates/app/components/ui/button.jsx +21 -0
  256. package/templates/app/components/ui/card.jsx +23 -0
  257. package/templates/app/components/ui/input.jsx +10 -0
  258. package/templates/app/components/ui/label.jsx +10 -0
  259. package/templates/app/crons/page.js +5 -0
  260. package/templates/app/findings/page.js +7 -0
  261. package/templates/app/globals.css +90 -0
  262. package/templates/app/layout.js +19 -0
  263. package/templates/app/login/page.js +15 -0
  264. package/templates/app/notifications/page.js +7 -0
  265. package/templates/app/page.js +7 -0
  266. package/templates/app/settings/crons/page.js +5 -0
  267. package/templates/app/settings/layout.js +7 -0
  268. package/templates/app/settings/mcp/page.js +5 -0
  269. package/templates/app/settings/page.js +5 -0
  270. package/templates/app/settings/secrets/page.js +5 -0
  271. package/templates/app/settings/triggers/page.js +5 -0
  272. package/templates/app/stream/chat/route.js +1 -0
  273. package/templates/app/swarm/page.js +7 -0
  274. package/templates/app/targets/page.js +7 -0
  275. package/templates/app/toolbox/page.js +7 -0
  276. package/templates/app/triggers/page.js +5 -0
  277. package/templates/config/AGENT.md +34 -0
  278. package/templates/config/CRONS.json +56 -0
  279. package/templates/config/EVENT_HANDLER.md +224 -0
  280. package/templates/config/HEARTBEAT.md +3 -0
  281. package/templates/config/JOB_SUMMARY.md +130 -0
  282. package/templates/config/MCP_SERVERS.json +1 -0
  283. package/templates/config/SKILL_BUILDING_GUIDE.md +90 -0
  284. package/templates/config/SOUL.md +17 -0
  285. package/templates/config/TRIGGERS.json +58 -0
  286. package/templates/docker/event-handler/Dockerfile +20 -0
  287. package/templates/docker/event-handler/ecosystem.config.cjs +8 -0
  288. package/templates/docker/job-claude-code/Dockerfile +34 -0
  289. package/templates/docker/job-claude-code/entrypoint.sh +139 -0
  290. package/templates/docker/job-pi-coding-agent/Dockerfile +44 -0
  291. package/templates/docker/job-pi-coding-agent/entrypoint.sh +163 -0
  292. package/templates/docker-compose.yml +63 -0
  293. package/templates/instrumentation.js +6 -0
  294. package/templates/middleware.js +1 -0
  295. package/templates/next.config.mjs +3 -0
  296. package/templates/postcss.config.mjs +5 -0
  297. package/templates/skills/LICENSE +21 -0
  298. package/templates/skills/README.md +119 -0
  299. package/templates/skills/brave-search/SKILL.md +79 -0
  300. package/templates/skills/brave-search/content.js +86 -0
  301. package/templates/skills/brave-search/package-lock.json +621 -0
  302. package/templates/skills/brave-search/package.json +14 -0
  303. package/templates/skills/brave-search/search.js +199 -0
  304. package/templates/skills/browser-tools/SKILL.md +196 -0
  305. package/templates/skills/browser-tools/browser-content.js +103 -0
  306. package/templates/skills/browser-tools/browser-cookies.js +35 -0
  307. package/templates/skills/browser-tools/browser-eval.js +53 -0
  308. package/templates/skills/browser-tools/browser-hn-scraper.js +108 -0
  309. package/templates/skills/browser-tools/browser-nav.js +44 -0
  310. package/templates/skills/browser-tools/browser-pick.js +162 -0
  311. package/templates/skills/browser-tools/browser-screenshot.js +34 -0
  312. package/templates/skills/browser-tools/browser-start.js +87 -0
  313. package/templates/skills/browser-tools/package-lock.json +2556 -0
  314. package/templates/skills/browser-tools/package.json +19 -0
  315. package/templates/skills/llm-secrets/SKILL.md +34 -0
  316. package/templates/skills/llm-secrets/llm-secrets.js +33 -0
  317. package/templates/skills/modify-self/SKILL.md +12 -0
@@ -0,0 +1,53 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef } from "react";
4
+ import { cn } from "../../utils.js";
5
+ function ConfirmDialog({ open, onConfirm, onCancel, title, description, confirmLabel = "Delete", cancelLabel = "Cancel", variant = "destructive" }) {
6
+ const cancelRef = useRef(null);
7
+ useEffect(() => {
8
+ if (open && cancelRef.current) {
9
+ cancelRef.current.focus();
10
+ }
11
+ }, [open]);
12
+ useEffect(() => {
13
+ if (!open) return;
14
+ const handleEsc = (e) => {
15
+ if (e.key === "Escape") onCancel();
16
+ };
17
+ document.addEventListener("keydown", handleEsc);
18
+ return () => document.removeEventListener("keydown", handleEsc);
19
+ }, [open, onCancel]);
20
+ if (!open) return null;
21
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
22
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/50", onClick: onCancel }),
23
+ /* @__PURE__ */ jsxs("div", { className: "relative z-50 w-full max-w-sm rounded-lg border border-border bg-background p-6 shadow-lg", onClick: (e) => e.stopPropagation(), children: [
24
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: title }),
25
+ description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: description }),
26
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [
27
+ /* @__PURE__ */ jsx(
28
+ "button",
29
+ {
30
+ ref: cancelRef,
31
+ onClick: onCancel,
32
+ className: "rounded-md px-3 py-1.5 text-sm font-medium border border-input bg-background hover:bg-muted",
33
+ children: cancelLabel
34
+ }
35
+ ),
36
+ /* @__PURE__ */ jsx(
37
+ "button",
38
+ {
39
+ onClick: onConfirm,
40
+ className: cn(
41
+ "rounded-md px-3 py-1.5 text-sm font-medium text-white",
42
+ variant === "destructive" ? "bg-destructive hover:bg-destructive/90" : "bg-foreground hover:bg-foreground/90"
43
+ ),
44
+ children: confirmLabel
45
+ }
46
+ )
47
+ ] })
48
+ ] })
49
+ ] });
50
+ }
51
+ export {
52
+ ConfirmDialog
53
+ };
@@ -0,0 +1,57 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useRef } from 'react';
4
+ import { cn } from '../../utils.js';
5
+
6
+ export function ConfirmDialog({ open, onConfirm, onCancel, title, description, confirmLabel = 'Delete', cancelLabel = 'Cancel', variant = 'destructive' }) {
7
+ const cancelRef = useRef(null);
8
+
9
+ useEffect(() => {
10
+ if (open && cancelRef.current) {
11
+ cancelRef.current.focus();
12
+ }
13
+ }, [open]);
14
+
15
+ useEffect(() => {
16
+ if (!open) return;
17
+ const handleEsc = (e) => {
18
+ if (e.key === 'Escape') onCancel();
19
+ };
20
+ document.addEventListener('keydown', handleEsc);
21
+ return () => document.removeEventListener('keydown', handleEsc);
22
+ }, [open, onCancel]);
23
+
24
+ if (!open) return null;
25
+
26
+ return (
27
+ <div className="fixed inset-0 z-50 flex items-center justify-center">
28
+ <div className="fixed inset-0 bg-black/50" onClick={onCancel} />
29
+ <div className="relative z-50 w-full max-w-sm rounded-lg border border-border bg-background p-6 shadow-lg" onClick={(e) => e.stopPropagation()}>
30
+ <h3 className="text-lg font-semibold">{title}</h3>
31
+ {description && (
32
+ <p className="mt-2 text-sm text-muted-foreground">{description}</p>
33
+ )}
34
+ <div className="mt-4 flex justify-end gap-2">
35
+ <button
36
+ ref={cancelRef}
37
+ onClick={onCancel}
38
+ className="rounded-md px-3 py-1.5 text-sm font-medium border border-input bg-background hover:bg-muted"
39
+ >
40
+ {cancelLabel}
41
+ </button>
42
+ <button
43
+ onClick={onConfirm}
44
+ className={cn(
45
+ 'rounded-md px-3 py-1.5 text-sm font-medium text-white',
46
+ variant === 'destructive'
47
+ ? 'bg-destructive hover:bg-destructive/90'
48
+ : 'bg-foreground hover:bg-foreground/90'
49
+ )}
50
+ >
51
+ {confirmLabel}
52
+ </button>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ );
57
+ }
@@ -0,0 +1,98 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useState, useEffect, useRef } from "react";
4
+ import { cn } from "../../utils.js";
5
+ const DropdownContext = createContext({ open: false, onOpenChange: () => {
6
+ } });
7
+ function DropdownMenu({ children, open: controlledOpen, onOpenChange: controlledOnOpenChange }) {
8
+ const [internalOpen, setInternalOpen] = useState(false);
9
+ const open = controlledOpen !== void 0 ? controlledOpen : internalOpen;
10
+ const onOpenChange = controlledOnOpenChange || setInternalOpen;
11
+ return /* @__PURE__ */ jsx(DropdownContext.Provider, { value: { open, onOpenChange }, children: /* @__PURE__ */ jsx("div", { className: "relative inline-block", children }) });
12
+ }
13
+ function DropdownMenuTrigger({ children, asChild, ...props }) {
14
+ const { open, onOpenChange } = useContext(DropdownContext);
15
+ const handleClick = (e) => {
16
+ e.stopPropagation();
17
+ onOpenChange(!open);
18
+ };
19
+ if (asChild && children) {
20
+ return /* @__PURE__ */ jsx("span", { onClick: handleClick, ...props, children });
21
+ }
22
+ return /* @__PURE__ */ jsx("button", { onClick: handleClick, ...props, children });
23
+ }
24
+ function DropdownMenuContent({ children, className, align = "start", side = "bottom", sideOffset = 4, ...props }) {
25
+ const { open, onOpenChange } = useContext(DropdownContext);
26
+ const ref = useRef(null);
27
+ useEffect(() => {
28
+ if (!open) return;
29
+ const handleClickOutside = (e) => {
30
+ if (ref.current && !ref.current.contains(e.target)) {
31
+ onOpenChange(false);
32
+ }
33
+ };
34
+ const handleEsc = (e) => {
35
+ if (e.key === "Escape") onOpenChange(false);
36
+ };
37
+ setTimeout(() => document.addEventListener("click", handleClickOutside), 0);
38
+ document.addEventListener("keydown", handleEsc);
39
+ return () => {
40
+ document.removeEventListener("click", handleClickOutside);
41
+ document.removeEventListener("keydown", handleEsc);
42
+ };
43
+ }, [open, onOpenChange]);
44
+ if (!open) return null;
45
+ return /* @__PURE__ */ jsx(
46
+ "div",
47
+ {
48
+ ref,
49
+ className: cn(
50
+ "absolute z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-background/80 backdrop-blur-sm p-1 text-foreground shadow-lg",
51
+ side === "bottom" && `top-full mt-1`,
52
+ side === "top" && `bottom-full mb-1`,
53
+ align === "end" && "right-0",
54
+ align === "start" && "left-0",
55
+ className
56
+ ),
57
+ ...props,
58
+ children
59
+ }
60
+ );
61
+ }
62
+ function DropdownMenuItem({ children, className, onClick, ...props }) {
63
+ const { onOpenChange } = useContext(DropdownContext);
64
+ return /* @__PURE__ */ jsx(
65
+ "div",
66
+ {
67
+ role: "menuitem",
68
+ className: cn(
69
+ "relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-background focus:bg-background",
70
+ className
71
+ ),
72
+ onClick: (e) => {
73
+ onClick?.(e);
74
+ onOpenChange(false);
75
+ },
76
+ ...props,
77
+ children
78
+ }
79
+ );
80
+ }
81
+ function DropdownMenuSeparator({ className }) {
82
+ return /* @__PURE__ */ jsx("div", { className: cn("-mx-1 my-1 h-px bg-border", className) });
83
+ }
84
+ function DropdownMenuLabel({ children, className }) {
85
+ return /* @__PURE__ */ jsx("div", { className: cn("px-2 py-1.5 text-sm font-semibold", className), children });
86
+ }
87
+ function DropdownMenuGroup({ children }) {
88
+ return /* @__PURE__ */ jsx("div", { children });
89
+ }
90
+ export {
91
+ DropdownMenu,
92
+ DropdownMenuContent,
93
+ DropdownMenuGroup,
94
+ DropdownMenuItem,
95
+ DropdownMenuLabel,
96
+ DropdownMenuSeparator,
97
+ DropdownMenuTrigger
98
+ };
@@ -0,0 +1,116 @@
1
+ 'use client';
2
+
3
+ import { createContext, useContext, useState, useEffect, useRef } from 'react';
4
+ import { cn } from '../../utils.js';
5
+
6
+ const DropdownContext = createContext({ open: false, onOpenChange: () => {} });
7
+
8
+ export function DropdownMenu({ children, open: controlledOpen, onOpenChange: controlledOnOpenChange }) {
9
+ const [internalOpen, setInternalOpen] = useState(false);
10
+ const open = controlledOpen !== undefined ? controlledOpen : internalOpen;
11
+ const onOpenChange = controlledOnOpenChange || setInternalOpen;
12
+
13
+ return (
14
+ <DropdownContext.Provider value={{ open, onOpenChange }}>
15
+ <div className="relative inline-block">{children}</div>
16
+ </DropdownContext.Provider>
17
+ );
18
+ }
19
+
20
+ export function DropdownMenuTrigger({ children, asChild, ...props }) {
21
+ const { open, onOpenChange } = useContext(DropdownContext);
22
+ const handleClick = (e) => {
23
+ e.stopPropagation();
24
+ onOpenChange(!open);
25
+ };
26
+ if (asChild && children) {
27
+ return (
28
+ <span onClick={handleClick} {...props}>
29
+ {children}
30
+ </span>
31
+ );
32
+ }
33
+ return (
34
+ <button onClick={handleClick} {...props}>
35
+ {children}
36
+ </button>
37
+ );
38
+ }
39
+
40
+ export function DropdownMenuContent({ children, className, align = 'start', side = 'bottom', sideOffset = 4, ...props }) {
41
+ const { open, onOpenChange } = useContext(DropdownContext);
42
+ const ref = useRef(null);
43
+
44
+ useEffect(() => {
45
+ if (!open) return;
46
+ const handleClickOutside = (e) => {
47
+ if (ref.current && !ref.current.contains(e.target)) {
48
+ onOpenChange(false);
49
+ }
50
+ };
51
+ const handleEsc = (e) => {
52
+ if (e.key === 'Escape') onOpenChange(false);
53
+ };
54
+ setTimeout(() => document.addEventListener('click', handleClickOutside), 0);
55
+ document.addEventListener('keydown', handleEsc);
56
+ return () => {
57
+ document.removeEventListener('click', handleClickOutside);
58
+ document.removeEventListener('keydown', handleEsc);
59
+ };
60
+ }, [open, onOpenChange]);
61
+
62
+ if (!open) return null;
63
+
64
+ return (
65
+ <div
66
+ ref={ref}
67
+ className={cn(
68
+ 'absolute z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-background/80 backdrop-blur-sm p-1 text-foreground shadow-lg',
69
+ side === 'bottom' && `top-full mt-1`,
70
+ side === 'top' && `bottom-full mb-1`,
71
+ align === 'end' && 'right-0',
72
+ align === 'start' && 'left-0',
73
+ className
74
+ )}
75
+ {...props}
76
+ >
77
+ {children}
78
+ </div>
79
+ );
80
+ }
81
+
82
+ export function DropdownMenuItem({ children, className, onClick, ...props }) {
83
+ const { onOpenChange } = useContext(DropdownContext);
84
+ return (
85
+ <div
86
+ role="menuitem"
87
+ className={cn(
88
+ 'relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors hover:bg-background focus:bg-background',
89
+ className
90
+ )}
91
+ onClick={(e) => {
92
+ onClick?.(e);
93
+ onOpenChange(false);
94
+ }}
95
+ {...props}
96
+ >
97
+ {children}
98
+ </div>
99
+ );
100
+ }
101
+
102
+ export function DropdownMenuSeparator({ className }) {
103
+ return <div className={cn('-mx-1 my-1 h-px bg-border', className)} />;
104
+ }
105
+
106
+ export function DropdownMenuLabel({ children, className }) {
107
+ return (
108
+ <div className={cn('px-2 py-1.5 text-sm font-semibold', className)}>
109
+ {children}
110
+ </div>
111
+ );
112
+ }
113
+
114
+ export function DropdownMenuGroup({ children }) {
115
+ return <div>{children}</div>;
116
+ }
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useEffect, useRef } from "react";
4
+ function RenameDialog({ open, onSave, onCancel, title = "Rename chat", currentValue = "" }) {
5
+ const [value, setValue] = useState(currentValue);
6
+ const inputRef = useRef(null);
7
+ useEffect(() => {
8
+ if (open) {
9
+ setValue(currentValue);
10
+ setTimeout(() => {
11
+ if (inputRef.current) {
12
+ inputRef.current.focus();
13
+ inputRef.current.select();
14
+ }
15
+ }, 0);
16
+ }
17
+ }, [open, currentValue]);
18
+ useEffect(() => {
19
+ if (!open) return;
20
+ const handleEsc = (e) => {
21
+ if (e.key === "Escape") onCancel();
22
+ };
23
+ document.addEventListener("keydown", handleEsc);
24
+ return () => document.removeEventListener("keydown", handleEsc);
25
+ }, [open, onCancel]);
26
+ const handleSave = () => {
27
+ const trimmed = value.trim();
28
+ if (trimmed && trimmed !== currentValue) {
29
+ onSave(trimmed);
30
+ }
31
+ onCancel();
32
+ };
33
+ if (!open) return null;
34
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
35
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 bg-black/50", onClick: onCancel }),
36
+ /* @__PURE__ */ jsxs("div", { className: "relative z-50 w-full max-w-sm rounded-lg border border-border bg-background p-6 shadow-lg", onClick: (e) => e.stopPropagation(), children: [
37
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: title }),
38
+ /* @__PURE__ */ jsx(
39
+ "input",
40
+ {
41
+ ref: inputRef,
42
+ type: "text",
43
+ value,
44
+ onChange: (e) => setValue(e.target.value),
45
+ onKeyDown: (e) => {
46
+ if (e.key === "Enter") handleSave();
47
+ },
48
+ className: "mt-3 w-full rounded-md border border-input bg-background px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
49
+ }
50
+ ),
51
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [
52
+ /* @__PURE__ */ jsx(
53
+ "button",
54
+ {
55
+ onClick: onCancel,
56
+ className: "rounded-md px-3 py-1.5 text-sm font-medium border border-input bg-background hover:bg-muted",
57
+ children: "Cancel"
58
+ }
59
+ ),
60
+ /* @__PURE__ */ jsx(
61
+ "button",
62
+ {
63
+ onClick: handleSave,
64
+ className: "rounded-md px-3 py-1.5 text-sm font-medium text-white bg-foreground hover:bg-foreground/90",
65
+ children: "Save"
66
+ }
67
+ )
68
+ ] })
69
+ ] })
70
+ ] });
71
+ }
72
+ export {
73
+ RenameDialog
74
+ };
@@ -0,0 +1,72 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useRef } from 'react';
4
+
5
+ export function RenameDialog({ open, onSave, onCancel, title = 'Rename chat', currentValue = '' }) {
6
+ const [value, setValue] = useState(currentValue);
7
+ const inputRef = useRef(null);
8
+
9
+ useEffect(() => {
10
+ if (open) {
11
+ setValue(currentValue);
12
+ setTimeout(() => {
13
+ if (inputRef.current) {
14
+ inputRef.current.focus();
15
+ inputRef.current.select();
16
+ }
17
+ }, 0);
18
+ }
19
+ }, [open, currentValue]);
20
+
21
+ useEffect(() => {
22
+ if (!open) return;
23
+ const handleEsc = (e) => {
24
+ if (e.key === 'Escape') onCancel();
25
+ };
26
+ document.addEventListener('keydown', handleEsc);
27
+ return () => document.removeEventListener('keydown', handleEsc);
28
+ }, [open, onCancel]);
29
+
30
+ const handleSave = () => {
31
+ const trimmed = value.trim();
32
+ if (trimmed && trimmed !== currentValue) {
33
+ onSave(trimmed);
34
+ }
35
+ onCancel();
36
+ };
37
+
38
+ if (!open) return null;
39
+
40
+ return (
41
+ <div className="fixed inset-0 z-50 flex items-center justify-center">
42
+ <div className="fixed inset-0 bg-black/50" onClick={onCancel} />
43
+ <div className="relative z-50 w-full max-w-sm rounded-lg border border-border bg-background p-6 shadow-lg" onClick={(e) => e.stopPropagation()}>
44
+ <h3 className="text-lg font-semibold">{title}</h3>
45
+ <input
46
+ ref={inputRef}
47
+ type="text"
48
+ value={value}
49
+ onChange={(e) => setValue(e.target.value)}
50
+ onKeyDown={(e) => {
51
+ if (e.key === 'Enter') handleSave();
52
+ }}
53
+ className="mt-3 w-full rounded-md border border-input bg-background px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
54
+ />
55
+ <div className="mt-4 flex justify-end gap-2">
56
+ <button
57
+ onClick={onCancel}
58
+ className="rounded-md px-3 py-1.5 text-sm font-medium border border-input bg-background hover:bg-muted"
59
+ >
60
+ Cancel
61
+ </button>
62
+ <button
63
+ onClick={handleSave}
64
+ className="rounded-md px-3 py-1.5 text-sm font-medium text-white bg-foreground hover:bg-foreground/90"
65
+ >
66
+ Save
67
+ </button>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ );
72
+ }
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { cn } from "../../utils.js";
4
+ function ScrollArea({ children, className, ...props }) {
5
+ return /* @__PURE__ */ jsx("div", { className: cn("relative overflow-hidden", className), ...props, children: /* @__PURE__ */ jsx("div", { className: "h-full w-full overflow-y-auto scrollbar-thin", children }) });
6
+ }
7
+ function ScrollBar() {
8
+ return null;
9
+ }
10
+ export {
11
+ ScrollArea,
12
+ ScrollBar
13
+ };
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+
3
+ import { cn } from '../../utils.js';
4
+
5
+ export function ScrollArea({ children, className, ...props }) {
6
+ return (
7
+ <div className={cn('relative overflow-hidden', className)} {...props}>
8
+ <div className="h-full w-full overflow-y-auto scrollbar-thin">
9
+ {children}
10
+ </div>
11
+ </div>
12
+ );
13
+ }
14
+
15
+ export function ScrollBar() {
16
+ return null;
17
+ }
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { cn } from "../../utils.js";
4
+ function Separator({ className, orientation = "horizontal", ...props }) {
5
+ return /* @__PURE__ */ jsx(
6
+ "div",
7
+ {
8
+ role: "separator",
9
+ "aria-orientation": orientation,
10
+ className: cn(
11
+ "shrink-0 bg-border",
12
+ orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
13
+ className
14
+ ),
15
+ ...props
16
+ }
17
+ );
18
+ }
19
+ export {
20
+ Separator
21
+ };
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+
3
+ import { cn } from '../../utils.js';
4
+
5
+ export function Separator({ className, orientation = 'horizontal', ...props }) {
6
+ return (
7
+ <div
8
+ role="separator"
9
+ aria-orientation={orientation}
10
+ className={cn(
11
+ 'shrink-0 bg-border',
12
+ orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
13
+ className
14
+ )}
15
+ {...props}
16
+ />
17
+ );
18
+ }
@@ -0,0 +1,75 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { createContext, useContext, useEffect } from "react";
4
+ import { cn } from "../../utils.js";
5
+ const SheetContext = createContext({ open: false, onOpenChange: () => {
6
+ } });
7
+ function Sheet({ children, open, onOpenChange }) {
8
+ return /* @__PURE__ */ jsx(SheetContext.Provider, { value: { open, onOpenChange }, children });
9
+ }
10
+ function SheetTrigger({ children, asChild, ...props }) {
11
+ const { onOpenChange } = useContext(SheetContext);
12
+ if (asChild && children) {
13
+ return /* @__PURE__ */ jsx("span", { onClick: () => onOpenChange(true), ...props, children });
14
+ }
15
+ return /* @__PURE__ */ jsx("button", { onClick: () => onOpenChange(true), ...props, children });
16
+ }
17
+ function SheetContent({ children, className, side = "left", ...props }) {
18
+ const { open, onOpenChange } = useContext(SheetContext);
19
+ useEffect(() => {
20
+ if (!open) return;
21
+ const handleEsc = (e) => {
22
+ if (e.key === "Escape") onOpenChange(false);
23
+ };
24
+ document.addEventListener("keydown", handleEsc);
25
+ return () => document.removeEventListener("keydown", handleEsc);
26
+ }, [open, onOpenChange]);
27
+ if (!open) return null;
28
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50", children: [
29
+ /* @__PURE__ */ jsx(
30
+ "div",
31
+ {
32
+ className: "fixed inset-0 bg-black/50",
33
+ onClick: () => onOpenChange(false)
34
+ }
35
+ ),
36
+ /* @__PURE__ */ jsx(
37
+ "div",
38
+ {
39
+ className: cn(
40
+ "fixed z-50 bg-background shadow-lg transition-transform",
41
+ side === "left" && "inset-y-0 left-0 w-3/4 max-w-sm border-r border-border",
42
+ side === "right" && "inset-y-0 right-0 w-3/4 max-w-sm border-l border-border",
43
+ className
44
+ ),
45
+ ...props,
46
+ children
47
+ }
48
+ )
49
+ ] });
50
+ }
51
+ function SheetHeader({ children, className }) {
52
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col space-y-2 p-4", className), children });
53
+ }
54
+ function SheetTitle({ children, className }) {
55
+ return /* @__PURE__ */ jsx("h2", { className: cn("text-lg font-semibold text-foreground", className), children });
56
+ }
57
+ function SheetDescription({ children, className }) {
58
+ return /* @__PURE__ */ jsx("p", { className: cn("text-sm text-muted-foreground", className), children });
59
+ }
60
+ function SheetClose({ children, asChild, ...props }) {
61
+ const { onOpenChange } = useContext(SheetContext);
62
+ if (asChild && children) {
63
+ return /* @__PURE__ */ jsx("span", { onClick: () => onOpenChange(false), ...props, children });
64
+ }
65
+ return /* @__PURE__ */ jsx("button", { onClick: () => onOpenChange(false), ...props, children });
66
+ }
67
+ export {
68
+ Sheet,
69
+ SheetClose,
70
+ SheetContent,
71
+ SheetDescription,
72
+ SheetHeader,
73
+ SheetTitle,
74
+ SheetTrigger
75
+ };