opencami 1.4.0 → 1.5.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 (77) hide show
  1. package/README.md +60 -0
  2. package/dist/client/assets/CSPContext-EgWK8bIJ.js +1 -0
  3. package/dist/client/assets/DirectionContext-DXtY05YF.js +1 -0
  4. package/dist/client/assets/_sessionKey-B89e7G3y.js +100 -0
  5. package/dist/client/assets/agents-screen-1BiEZ9od.js +1 -0
  6. package/dist/client/assets/agents-x54ocA9z.js +2 -0
  7. package/dist/client/assets/bots-screen-BNQciUeJ.js +1 -0
  8. package/dist/client/assets/bots-x86ZHG4b.js +2 -0
  9. package/dist/client/assets/button-nDcsaNPl.js +1 -0
  10. package/dist/client/assets/{connect-D3baVDFL.js → connect-w4lLOqiJ.js} +1 -1
  11. package/dist/client/assets/file-explorer-screen-CAsjd3w8.js +1 -0
  12. package/dist/client/assets/files-Bype5Mnb.js +2 -0
  13. package/dist/client/assets/{index-ByIsZcHh.js → index-36G0WCxU.js} +1 -1
  14. package/dist/client/assets/{index-CVV4XiZo.js → index-BXkRE220.js} +2 -2
  15. package/dist/client/assets/keyboard-shortcuts-dialog-BdCeXRjD.js +1 -0
  16. package/dist/client/assets/{main-CkIF0soY.js → main-B3N0eQFg.js} +129 -17
  17. package/dist/client/assets/{opencami-logo-CIxSO1oo.js → opencami-logo-DD0DPFRQ.js} +1 -1
  18. package/dist/client/assets/{react-BhVdgA5r.js → react-B16OrBeM.js} +1 -1
  19. package/dist/client/assets/search-dialog-BjTPceEl.js +1 -0
  20. package/dist/client/assets/session-export-dialog-DtHKG2zW.js +1 -0
  21. package/dist/client/assets/settings-dialog-hiqdk_UD.js +1 -0
  22. package/dist/client/assets/skills-DhwyFq3y.js +2 -0
  23. package/dist/client/assets/skills-panel-BLUjzfjJ.js +5 -0
  24. package/dist/client/assets/styles-CHP4l6vZ.css +1 -0
  25. package/dist/client/assets/switch-J6wLIVu2.js +1 -0
  26. package/dist/client/assets/tabs-DvPgTz5I.js +1 -0
  27. package/dist/client/assets/tooltip-C14vdXHK.js +1 -0
  28. package/dist/client/assets/use-file-explorer-state-BnaJEqRP.js +12 -0
  29. package/dist/client/assets/useButton-Bnnac1eR.js +1 -0
  30. package/dist/client/assets/useCompositeItem-BgiEMKAt.js +1 -0
  31. package/dist/client/assets/{useControlled-Y306krcC.js → useControlled-BhUuiHAm.js} +1 -1
  32. package/dist/client/assets/{useMutation-0WgW4xQJ.js → useMutation-CFmVaBag.js} +1 -1
  33. package/dist/client/assets/visuallyHidden-DCCICp6T.js +9 -0
  34. package/dist/server/assets/{_sessionKey-BhFH4uWY.js → _sessionKey-tRze5NLR.js} +178 -46
  35. package/dist/server/assets/_tanstack-start-manifest_v-CyfoMvUa.js +4 -0
  36. package/dist/server/assets/{agents-Dz_i76VW.js → agents-CmQ4vvXm.js} +1 -1
  37. package/dist/server/assets/{agents-screen-CqQPJndp.js → agents-screen-bmrIyFbk.js} +43 -35
  38. package/dist/server/assets/{bots-6ryCIgKh.js → bots-Byt6jv0a.js} +1 -1
  39. package/dist/server/assets/bots-screen-C2TGFv42.js +474 -0
  40. package/dist/server/assets/{button-DtQ3rV1m.js → button-CwY2OHFj.js} +2 -2
  41. package/dist/server/assets/{connect-B8jpGQGK.js → connect-d3AqjAqe.js} +2 -2
  42. package/dist/server/assets/{file-explorer-screen-DCfS_Ajx.js → file-explorer-screen-CVlFiAFu.js} +36 -36
  43. package/dist/server/assets/{files-D2GIrPF4.js → files-BIEcSPGp.js} +1 -1
  44. package/dist/server/assets/{index-BNSsDaLb.js → index-CNIATlJ9.js} +22 -3
  45. package/dist/server/assets/{index-B2JHn34C.js → index-CRfLKh30.js} +2 -1
  46. package/dist/server/assets/{keyboard-shortcuts-dialog-CqIm8aYF.js → keyboard-shortcuts-dialog-CsNP85q8.js} +2 -2
  47. package/dist/server/assets/{router-Dme7USeO.js → router-rn7pJO_D.js} +356 -64
  48. package/dist/server/assets/{search-dialog-DG0D9KRN.js → search-dialog-Bz4Cu0KW.js} +23 -6
  49. package/dist/server/assets/{session-export-dialog-DLPZVlQV.js → session-export-dialog-CwclV0Aj.js} +2 -2
  50. package/dist/server/assets/{settings-dialog-BaGT4e5l.js → settings-dialog-BBM7jCjE.js} +386 -95
  51. package/dist/server/assets/skills-Cy8xclXY.js +11 -0
  52. package/dist/server/assets/skills-panel-BnRNb7u9.js +762 -0
  53. package/dist/server/assets/{switch-DnX0MjGS.js → switch-BbkUeVDV.js} +1 -1
  54. package/dist/server/assets/tabs-DDFZob0m.js +67 -0
  55. package/dist/server/assets/{tooltip-gbV6rEVv.js → tooltip-DgsSPocE.js} +1 -1
  56. package/dist/server/assets/{use-file-explorer-state-DfAKF2gZ.js → use-file-explorer-state-Il1LlBAe.js} +1 -1
  57. package/dist/server/server.js +2 -2
  58. package/package.json +6 -2
  59. package/dist/client/assets/_sessionKey-DB95zj1L.js +0 -97
  60. package/dist/client/assets/agents-LFrWe-HX.js +0 -2
  61. package/dist/client/assets/agents-screen-CEBBk1yO.js +0 -1
  62. package/dist/client/assets/bots-CxDwf_WK.js +0 -2
  63. package/dist/client/assets/bots-screen-D6qma1wK.js +0 -1
  64. package/dist/client/assets/button-Il3CHIzX.js +0 -1
  65. package/dist/client/assets/file-explorer-screen-rtV6n-5_.js +0 -1
  66. package/dist/client/assets/files-DMemuq9D.js +0 -2
  67. package/dist/client/assets/keyboard-shortcuts-dialog-DXC0YHoy.js +0 -1
  68. package/dist/client/assets/search-dialog-I1jJplIh.js +0 -1
  69. package/dist/client/assets/session-export-dialog-CH5unryw.js +0 -1
  70. package/dist/client/assets/settings-dialog-B8v-GVJ8.js +0 -1
  71. package/dist/client/assets/styles-BaTVzdPa.css +0 -1
  72. package/dist/client/assets/switch-sQnv1YsK.js +0 -1
  73. package/dist/client/assets/tooltip-j_viC_EE.js +0 -1
  74. package/dist/client/assets/use-file-explorer-state-BUH-u7Jv.js +0 -12
  75. package/dist/client/assets/useButton-9VAzplAB.js +0 -9
  76. package/dist/server/assets/_tanstack-start-manifest_v-BaIrL1VQ.js +0 -4
  77. package/dist/server/assets/bots-screen-DS_ZF9Ec.js +0 -417
@@ -1,13 +1,13 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useState, useRef, useEffect } from "react";
3
- import { c as cn, B as Button } from "./button-DtQ3rV1m.js";
2
+ import { useState, useEffect, useRef } from "react";
3
+ import { B as Button, c as cn } from "./button-CwY2OHFj.js";
4
4
  import { HugeiconsIcon } from "@hugeicons/react";
5
- import { Cancel01Icon, Link01Icon, PaintBoardIcon, MessageEdit01Icon, UserIcon, VoiceIcon, AiBrain01Icon, InformationCircleIcon, ComputerIcon, Sun01Icon, Moon01Icon, Leaf01Icon, Loading02Icon, Tick01Icon, Cancel02Icon } from "@hugeicons/core-free-icons";
6
- import { D as DialogRoot, a as DialogContent, b as DialogTitle, c as DialogDescription, d as DialogClose } from "./use-file-explorer-state-DfAKF2gZ.js";
7
- import { S as Switch } from "./switch-DnX0MjGS.js";
8
- import { Tabs as Tabs$1 } from "@base-ui/react/tabs";
9
- import { u as useChatSettings } from "./index-BNSsDaLb.js";
10
- import { u as useLlmSettings, g as getLlmProviderDefaults } from "./_sessionKey-BhFH4uWY.js";
5
+ import { Cancel01Icon, Link01Icon, PaintBoardIcon, MessageEdit01Icon, UserIcon, VoiceIcon, AiBrain01Icon, InformationCircleIcon, ComputerIcon, Sun01Icon, Moon01Icon, Leaf01Icon, DropletIcon, Loading02Icon, Tick01Icon, Cancel02Icon } from "@hugeicons/core-free-icons";
6
+ import { D as DialogRoot, a as DialogContent, b as DialogTitle, c as DialogDescription, d as DialogClose } from "./use-file-explorer-state-Il1LlBAe.js";
7
+ import { S as Switch } from "./switch-BbkUeVDV.js";
8
+ import { T as Tabs, a as TabsList, b as TabsTab } from "./tabs-DDFZob0m.js";
9
+ import { u as useChatSettings } from "./index-CNIATlJ9.js";
10
+ import { u as useLlmSettings, g as getLlmProviderDefaults } from "./_sessionKey-tRze5NLR.js";
11
11
  import "@base-ui/react/merge-props";
12
12
  import "@base-ui/react/use-render";
13
13
  import "class-variance-authority";
@@ -17,6 +17,7 @@ import "@base-ui/react/dialog";
17
17
  import "@base-ui/react/menu";
18
18
  import "zustand";
19
19
  import "@base-ui/react/switch";
20
+ import "@base-ui/react/tabs";
20
21
  import "shiki/core";
21
22
  import "shiki/engine/javascript";
22
23
  import "@shikijs/themes/vitesse-dark";
@@ -53,7 +54,7 @@ import "@shikijs/langs/yaml";
53
54
  import "zustand/middleware";
54
55
  import "@tanstack/react-router";
55
56
  import "@tanstack/react-query";
56
- import "./tooltip-gbV6rEVv.js";
57
+ import "./tooltip-DgsSPocE.js";
57
58
  import "@base-ui/react/tooltip";
58
59
  import "motion/react";
59
60
  import "@base-ui/react/alert-dialog";
@@ -65,91 +66,42 @@ import "react-markdown";
65
66
  import "remark-breaks";
66
67
  import "remark-gfm";
67
68
  import "react-dom";
68
- import "./router-Dme7USeO.js";
69
+ import "./router-rn7pJO_D.js";
69
70
  import "node:crypto";
70
71
  import "ws";
71
72
  import "node:fs";
72
73
  import "node:path";
73
74
  import "node:os";
74
75
  import "@tanstack/router-core/ssr/client";
76
+ import "node:child_process";
75
77
  import "node:fs/promises";
76
78
  import "path";
77
- function Tabs({ className, ...props }) {
78
- return /* @__PURE__ */ jsx(
79
- Tabs$1.Root,
80
- {
81
- className: cn(
82
- "flex flex-col gap-2 data-[orientation=vertical]:flex-row",
83
- className
84
- ),
85
- "data-slot": "tabs",
86
- ...props
87
- }
88
- );
89
- }
90
- function TabsList({
91
- variant = "default",
92
- className,
93
- children,
94
- ...props
95
- }) {
96
- return /* @__PURE__ */ jsxs(
97
- Tabs$1.List,
98
- {
99
- className: cn(
100
- "relative z-0 flex w-fit items-center justify-center gap-x-0.5 text-primary-600",
101
- "data-[orientation=vertical]:flex-col",
102
- variant === "default" ? "p-0.5 text-primary-600/80" : "data-[orientation=vertical]:px-1 data-[orientation=horizontal]:py-1",
103
- className
104
- ),
105
- "data-slot": "tabs-list",
106
- ...props,
107
- children: [
108
- children,
109
- /* @__PURE__ */ jsx(
110
- Tabs$1.Indicator,
111
- {
112
- className: cn(
113
- "-translate-y-(--active-tab-bottom) absolute bottom-0 left-0 h-(--active-tab-height) w-(--active-tab-width) translate-x-(--active-tab-left) transition-[width,translate] duration-200 ease-in-out",
114
- variant === "underline" ? "data-[orientation=vertical]:-translate-x-px z-10 bg-primary-900 data-[orientation=horizontal]:h-0.5 data-[orientation=vertical]:w-0.5 data-[orientation=horizontal]:translate-y-px" : "z-0 rounded-md bg-primary-200"
115
- ),
116
- "data-slot": "tab-indicator"
117
- }
118
- )
119
- ]
120
- }
121
- );
122
- }
123
- function TabsTab({ className, ...props }) {
124
- return /* @__PURE__ */ jsx(
125
- Tabs$1.Tab,
126
- {
127
- className: cn(
128
- '[&_svg]:-mx-0.5 relative z-10 flex h-8 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md px-3 text-sm font-medium outline-none transition-[color,background-color,box-shadow] hover:text-primary-900 focus-visible:ring-2 focus-visible:ring-primary-400 data-disabled:pointer-events-none data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start data-active:text-primary-900 data-disabled:opacity-64 [&_svg:not([class*="size-"])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0',
129
- className
130
- ),
131
- "data-slot": "tabs-tab",
132
- ...props
133
- }
134
- );
135
- }
136
79
  function SettingsSection({ title, tabId, activeTab, children }) {
137
80
  const hiddenOnDesktop = tabId && activeTab && tabId !== activeTab;
138
81
  return /* @__PURE__ */ jsxs("div", { className: cn(
139
- "border-b border-primary-200 py-4 last:border-0",
82
+ "border-b border-primary-200 py-2 last:border-0",
140
83
  hiddenOnDesktop && "md:hidden"
141
84
  ), children: [
142
- /* @__PURE__ */ jsx("h3", { className: "mb-3 text-sm font-medium text-primary-900", children: title }),
143
- /* @__PURE__ */ jsx("div", { className: "space-y-3", children })
85
+ /* @__PURE__ */ jsx("h3", { className: "mb-1.5 text-sm font-semibold text-primary-700", children: title }),
86
+ /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children })
144
87
  ] });
145
88
  }
146
- function SettingsRow({ label, description, children }) {
147
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
148
- /* @__PURE__ */ jsxs("div", { className: "flex-1 select-none", children: [
149
- /* @__PURE__ */ jsx("div", { className: "text-sm text-primary-800", children: label }),
89
+ function SettingsRow({ label, description, inline, children }) {
90
+ if (inline) {
91
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
92
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 select-none", children: [
93
+ /* @__PURE__ */ jsx("div", { className: "text-[13px] font-medium text-primary-800", children: label }),
94
+ description && /* @__PURE__ */ jsx("div", { className: "text-xs text-primary-500", children: description })
95
+ ] }),
96
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children })
97
+ ] });
98
+ }
99
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
100
+ /* @__PURE__ */ jsxs("div", { className: "select-none", children: [
101
+ /* @__PURE__ */ jsx("div", { className: "text-[13px] font-medium text-primary-800", children: label }),
150
102
  description && /* @__PURE__ */ jsx("div", { className: "text-xs text-primary-500", children: description })
151
103
  ] }),
152
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children })
104
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 flex-wrap", children })
153
105
  ] });
154
106
  }
155
107
  const textSizeOptions = [
@@ -158,9 +110,79 @@ const textSizeOptions = [
158
110
  { value: "18px", label: "L" },
159
111
  { value: "20px", label: "XL" }
160
112
  ];
113
+ const fontFamilyOptions = [
114
+ {
115
+ value: "system",
116
+ label: "System",
117
+ cssValue: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
118
+ previewClass: "font-sans"
119
+ },
120
+ {
121
+ value: "inter",
122
+ label: "Inter",
123
+ cssValue: '"Inter", sans-serif',
124
+ previewClass: 'font-["Inter",sans-serif]'
125
+ },
126
+ {
127
+ value: "roboto",
128
+ label: "Roboto",
129
+ cssValue: '"Roboto", sans-serif',
130
+ previewClass: 'font-["Roboto",sans-serif]'
131
+ }
132
+ ];
133
+ const densityOptions = [
134
+ { value: "compact", label: "Compact" },
135
+ { value: "comfortable", label: "Comfortable" },
136
+ { value: "spacious", label: "Spacious" }
137
+ ];
138
+ const accentColorOptions = [
139
+ { value: "green", label: "Green", accent: "#22c55e", hover: "#16a34a", light: "rgba(34, 197, 94, 0.10)" },
140
+ { value: "blue", label: "Blue", accent: "#3b82f6", hover: "#2563eb", light: "rgba(59, 130, 246, 0.10)" },
141
+ { value: "purple", label: "Purple", accent: "#8b5cf6", hover: "#7c3aed", light: "rgba(139, 92, 246, 0.10)" },
142
+ { value: "orange", label: "Orange", accent: "#f97316", hover: "#ea580c", light: "rgba(249, 115, 22, 0.10)" },
143
+ { value: "pink", label: "Pink", accent: "#ec4899", hover: "#db2777", light: "rgba(236, 72, 153, 0.10)" },
144
+ { value: "red", label: "Red", accent: "#ef4444", hover: "#dc2626", light: "rgba(239, 68, 68, 0.10)" },
145
+ { value: "cyan", label: "Cyan", accent: "#06b6d4", hover: "#0891b2", light: "rgba(6, 182, 212, 0.10)" },
146
+ { value: "yellow", label: "Yellow", accent: "#eab308", hover: "#ca8a04", light: "rgba(234, 179, 8, 0.10)" }
147
+ ];
148
+ const chatWidthOptions = [
149
+ { value: "narrow", label: "Narrow", cssValue: "640px" },
150
+ { value: "medium", label: "Medium", cssValue: "800px" },
151
+ { value: "wide", label: "Wide", cssValue: "1000px" },
152
+ { value: "full", label: "Full", cssValue: "100%" }
153
+ ];
154
+ const sidebarWidthOptions = [
155
+ { value: "compact", label: "Compact", cssValue: "200px" },
156
+ { value: "normal", label: "Normal", cssValue: "260px" },
157
+ { value: "wide", label: "Wide", cssValue: "320px" },
158
+ { value: "xl", label: "XL", cssValue: "400px" }
159
+ ];
160
+ const bubbleStyleOptions = [
161
+ { value: "default", label: "Default" },
162
+ { value: "bubbles", label: "Bubbles" },
163
+ { value: "minimal", label: "Minimal" }
164
+ ];
161
165
  function isTextSizeValue(value) {
162
166
  return textSizeOptions.some((option) => option.value === value);
163
167
  }
168
+ function isFontFamilyValue(value) {
169
+ return fontFamilyOptions.some((option) => option.value === value);
170
+ }
171
+ function isDensityValue(value) {
172
+ return densityOptions.some((option) => option.value === value);
173
+ }
174
+ function isAccentColorValue(value) {
175
+ return accentColorOptions.some((option) => option.value === value);
176
+ }
177
+ function isChatWidthValue(value) {
178
+ return chatWidthOptions.some((option) => option.value === value);
179
+ }
180
+ function isSidebarWidthValue(value) {
181
+ return sidebarWidthOptions.some((option) => option.value === value);
182
+ }
183
+ function isBubbleStyleValue(value) {
184
+ return bubbleStyleOptions.some((option) => option.value === value);
185
+ }
164
186
  function SettingsDialog({
165
187
  open,
166
188
  onOpenChange,
@@ -219,6 +241,90 @@ function SettingsDialog({
219
241
  return "auto";
220
242
  }
221
243
  });
244
+ useEffect(() => {
245
+ if (typeof window === "undefined") return;
246
+ try {
247
+ const storedFontFamily = localStorage.getItem("opencami-font-family");
248
+ if (storedFontFamily && isFontFamilyValue(storedFontFamily)) {
249
+ applyFontFamily(storedFontFamily);
250
+ if (settings.fontFamily !== storedFontFamily) {
251
+ updateSettings({ fontFamily: storedFontFamily });
252
+ }
253
+ } else {
254
+ applyFontFamily(settings.fontFamily);
255
+ }
256
+ const storedDensity = localStorage.getItem("opencami-density");
257
+ if (storedDensity && isDensityValue(storedDensity)) {
258
+ applyDensity(storedDensity);
259
+ if (settings.density !== storedDensity) {
260
+ updateSettings({ density: storedDensity });
261
+ }
262
+ } else {
263
+ applyDensity(settings.density);
264
+ }
265
+ const storedAccentColor = localStorage.getItem("opencami-accent-color");
266
+ if (storedAccentColor && isAccentColorValue(storedAccentColor)) {
267
+ applyAccentColor(storedAccentColor);
268
+ if (settings.accentColor !== storedAccentColor) {
269
+ updateSettings({ accentColor: storedAccentColor });
270
+ }
271
+ } else {
272
+ applyAccentColor(settings.accentColor);
273
+ }
274
+ const storedChatWidth = localStorage.getItem("opencami-chat-width");
275
+ if (storedChatWidth && isChatWidthValue(storedChatWidth)) {
276
+ applyChatWidth(storedChatWidth);
277
+ if (settings.chatWidth !== storedChatWidth) {
278
+ updateSettings({ chatWidth: storedChatWidth });
279
+ }
280
+ } else {
281
+ applyChatWidth(settings.chatWidth);
282
+ }
283
+ const storedSidebarWidth = localStorage.getItem("opencami-sidebar-width");
284
+ if (storedSidebarWidth && isSidebarWidthValue(storedSidebarWidth)) {
285
+ applySidebarWidth(storedSidebarWidth);
286
+ if (settings.sidebarWidth !== storedSidebarWidth) {
287
+ updateSettings({ sidebarWidth: storedSidebarWidth });
288
+ }
289
+ } else {
290
+ applySidebarWidth(settings.sidebarWidth);
291
+ }
292
+ const storedBubbleStyle = localStorage.getItem("opencami-bubble-style");
293
+ if (storedBubbleStyle && isBubbleStyleValue(storedBubbleStyle)) {
294
+ applyBubbleStyle(storedBubbleStyle);
295
+ if (settings.bubbleStyle !== storedBubbleStyle) {
296
+ updateSettings({ bubbleStyle: storedBubbleStyle });
297
+ }
298
+ } else {
299
+ applyBubbleStyle(settings.bubbleStyle);
300
+ }
301
+ } catch {
302
+ applyFontFamily(settings.fontFamily);
303
+ applyDensity(settings.density);
304
+ applyAccentColor(settings.accentColor);
305
+ applyChatWidth(settings.chatWidth);
306
+ applySidebarWidth(settings.sidebarWidth);
307
+ applyBubbleStyle(settings.bubbleStyle);
308
+ }
309
+ }, []);
310
+ useEffect(() => {
311
+ applyFontFamily(settings.fontFamily);
312
+ }, [settings.fontFamily]);
313
+ useEffect(() => {
314
+ applyDensity(settings.density);
315
+ }, [settings.density]);
316
+ useEffect(() => {
317
+ applyAccentColor(settings.accentColor);
318
+ }, [settings.accentColor]);
319
+ useEffect(() => {
320
+ applyChatWidth(settings.chatWidth);
321
+ }, [settings.chatWidth]);
322
+ useEffect(() => {
323
+ applySidebarWidth(settings.sidebarWidth);
324
+ }, [settings.sidebarWidth]);
325
+ useEffect(() => {
326
+ applyBubbleStyle(settings.bubbleStyle);
327
+ }, [settings.bubbleStyle]);
222
328
  const handleTtsProviderChange = (value) => {
223
329
  setTtsProvider(value);
224
330
  try {
@@ -244,6 +350,54 @@ function SettingsDialog({
244
350
  if (typeof document === "undefined") return;
245
351
  document.documentElement.style.setProperty("--opencami-text-size", value);
246
352
  }
353
+ function applyFontFamily(value) {
354
+ if (typeof document === "undefined") return;
355
+ const selected = fontFamilyOptions.find((option) => option.value === value);
356
+ const cssValue = selected?.cssValue ?? fontFamilyOptions[0].cssValue;
357
+ document.documentElement.style.setProperty("--opencami-font-family", cssValue);
358
+ }
359
+ function applyDensity(value) {
360
+ if (typeof document === "undefined") return;
361
+ const root = document.documentElement;
362
+ root.style.setProperty("--opencami-density", value);
363
+ if (value === "compact") {
364
+ root.style.setProperty("--opencami-msg-padding-y", "0.25rem");
365
+ root.style.setProperty("--opencami-msg-gap", "0.25rem");
366
+ root.style.setProperty("--opencami-user-bubble-py", "0.4rem");
367
+ return;
368
+ }
369
+ if (value === "spacious") {
370
+ root.style.setProperty("--opencami-msg-padding-y", "1.25rem");
371
+ root.style.setProperty("--opencami-msg-gap", "1rem");
372
+ root.style.setProperty("--opencami-user-bubble-py", "1rem");
373
+ return;
374
+ }
375
+ root.style.setProperty("--opencami-msg-padding-y", "0.75rem");
376
+ root.style.setProperty("--opencami-msg-gap", "0.5rem");
377
+ root.style.setProperty("--opencami-user-bubble-py", "0.625rem");
378
+ }
379
+ function applyAccentColor(value) {
380
+ if (typeof document === "undefined") return;
381
+ const selected = accentColorOptions.find((option) => option.value === value) ?? accentColorOptions[0];
382
+ const root = document.documentElement;
383
+ root.style.setProperty("--opencami-accent", selected.accent);
384
+ root.style.setProperty("--opencami-accent-hover", selected.hover);
385
+ root.style.setProperty("--opencami-accent-light", selected.light);
386
+ }
387
+ function applyChatWidth(value) {
388
+ if (typeof document === "undefined") return;
389
+ const selected = chatWidthOptions.find((option) => option.value === value) ?? chatWidthOptions[2];
390
+ document.documentElement.style.setProperty("--opencami-chat-width", selected.cssValue);
391
+ }
392
+ function applySidebarWidth(value) {
393
+ if (typeof document === "undefined") return;
394
+ const selected = sidebarWidthOptions.find((option) => option.value === value) ?? sidebarWidthOptions[1];
395
+ document.documentElement.style.setProperty("--opencami-sidebar-width", selected.cssValue);
396
+ }
397
+ function applyBubbleStyle(value) {
398
+ if (typeof document === "undefined") return;
399
+ document.documentElement.setAttribute("data-opencami-bubble-style", value);
400
+ }
247
401
  const handleTextSizeChange = (value) => {
248
402
  if (!isTextSizeValue(value)) return;
249
403
  setTextSize(value);
@@ -253,6 +407,60 @@ function SettingsDialog({
253
407
  } catch {
254
408
  }
255
409
  };
410
+ const handleFontFamilyChange = (value) => {
411
+ if (!isFontFamilyValue(value)) return;
412
+ applyFontFamily(value);
413
+ updateSettings({ fontFamily: value });
414
+ try {
415
+ localStorage.setItem("opencami-font-family", value);
416
+ } catch {
417
+ }
418
+ };
419
+ const handleDensityChange = (value) => {
420
+ if (!isDensityValue(value)) return;
421
+ applyDensity(value);
422
+ updateSettings({ density: value });
423
+ try {
424
+ localStorage.setItem("opencami-density", value);
425
+ } catch {
426
+ }
427
+ };
428
+ const handleAccentColorChange = (value) => {
429
+ if (!isAccentColorValue(value)) return;
430
+ applyAccentColor(value);
431
+ updateSettings({ accentColor: value });
432
+ try {
433
+ localStorage.setItem("opencami-accent-color", value);
434
+ } catch {
435
+ }
436
+ };
437
+ const handleChatWidthChange = (value) => {
438
+ if (!isChatWidthValue(value)) return;
439
+ applyChatWidth(value);
440
+ updateSettings({ chatWidth: value });
441
+ try {
442
+ localStorage.setItem("opencami-chat-width", value);
443
+ } catch {
444
+ }
445
+ };
446
+ const handleSidebarWidthChange = (value) => {
447
+ if (!isSidebarWidthValue(value)) return;
448
+ applySidebarWidth(value);
449
+ updateSettings({ sidebarWidth: value });
450
+ try {
451
+ localStorage.setItem("opencami-sidebar-width", value);
452
+ } catch {
453
+ }
454
+ };
455
+ const handleBubbleStyleChange = (value) => {
456
+ if (!isBubbleStyleValue(value)) return;
457
+ applyBubbleStyle(value);
458
+ updateSettings({ bubbleStyle: value });
459
+ try {
460
+ localStorage.setItem("opencami-bubble-style", value);
461
+ } catch {
462
+ }
463
+ };
256
464
  const handleTtsToggle = (checked) => {
257
465
  setTtsEnabled(checked);
258
466
  try {
@@ -333,22 +541,30 @@ function SettingsDialog({
333
541
  setTestResult(null);
334
542
  };
335
543
  const themeOptions = [
336
- { value: "system", label: "System", icon: ComputerIcon },
544
+ { value: "system", label: "Auto", icon: ComputerIcon },
337
545
  { value: "light", label: "Light", icon: Sun01Icon },
338
546
  { value: "dark", label: "Dark", icon: Moon01Icon },
339
- { value: "chameleon", label: "Chameleon", icon: Leaf01Icon }
547
+ { value: "chameleon", label: "Cham", icon: Leaf01Icon },
548
+ { value: "frost-light", label: "Ice", icon: DropletIcon },
549
+ { value: "frost-dark", label: "Noir", icon: DropletIcon }
340
550
  ];
341
551
  function applyTheme(theme) {
342
552
  if (typeof document === "undefined") return;
343
553
  const root = document.documentElement;
344
554
  const media = window.matchMedia("(prefers-color-scheme: dark)");
345
- root.classList.remove("light", "dark", "system", "chameleon");
555
+ root.classList.remove("light", "dark", "system", "chameleon", "frost", "frost-light", "frost-dark");
346
556
  root.classList.add(theme);
557
+ if (theme === "frost-light" || theme === "frost-dark") {
558
+ root.classList.add("frost");
559
+ }
560
+ if (theme === "frost-dark") {
561
+ root.classList.add("dark");
562
+ }
347
563
  if (theme === "system" && media.matches) {
348
564
  root.classList.add("dark");
349
565
  }
350
566
  }
351
- return /* @__PURE__ */ jsx(DialogRoot, { open, onOpenChange, children: /* @__PURE__ */ jsx(DialogContent, { className: "w-[min(720px,92vw)] max-h-[80vh] overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
567
+ return /* @__PURE__ */ jsx(DialogRoot, { open, onOpenChange, children: /* @__PURE__ */ jsx(DialogContent, { className: "w-[min(680px,92vw)] max-h-[85vh] overflow-y-auto", children: /* @__PURE__ */ jsxs("div", { className: "p-3", children: [
352
568
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
353
569
  /* @__PURE__ */ jsxs("div", { children: [
354
570
  /* @__PURE__ */ jsx(DialogTitle, { className: "mb-1", children: "Settings" }),
@@ -377,7 +593,7 @@ function SettingsDialog({
377
593
  }
378
594
  )
379
595
  ] }),
380
- /* @__PURE__ */ jsxs("div", { className: "mt-3 flex md:flex-row flex-col md:gap-4 gap-0 md:min-h-[400px]", children: [
596
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex md:flex-row flex-col md:gap-3 gap-0 md:min-h-[400px]", children: [
381
597
  /* @__PURE__ */ jsx("nav", { className: "hidden md:flex flex-col gap-0.5 min-w-[160px] border-r border-primary-200 pr-3", children: [
382
598
  { id: "connection", label: "Connection", icon: Link01Icon },
383
599
  { id: "appearance", label: "Appearance", icon: PaintBoardIcon },
@@ -392,8 +608,9 @@ function SettingsDialog({
392
608
  onClick: () => setActiveTab(tab.id),
393
609
  className: cn(
394
610
  "flex items-center gap-2 px-2.5 py-1.5 rounded-md text-sm text-left transition-colors",
395
- activeTab === tab.id ? "bg-primary-100 text-primary-900 font-medium" : "text-primary-600 hover:text-primary-900 hover:bg-primary-50"
611
+ activeTab === tab.id ? "text-primary-900 font-medium" : "text-primary-600 hover:text-primary-900 hover:bg-primary-50"
396
612
  ),
613
+ style: activeTab === tab.id ? { backgroundColor: "var(--opencami-accent-light)" } : void 0,
397
614
  children: [
398
615
  /* @__PURE__ */ jsx(HugeiconsIcon, { icon: tab.icon, size: 16, strokeWidth: 1.5 }),
399
616
  tab.label
@@ -401,8 +618,8 @@ function SettingsDialog({
401
618
  },
402
619
  tab.id
403
620
  )) }),
404
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto md:max-h-[calc(80vh-100px)] max-h-none", children: [
405
- /* @__PURE__ */ jsx(SettingsSection, { title: "Connection", tabId: "connection", activeTab, children: /* @__PURE__ */ jsx(SettingsRow, { label: "Status", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-sm text-green-600", children: [
621
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto md:max-h-[calc(85vh-90px)] max-h-none", children: [
622
+ /* @__PURE__ */ jsx(SettingsSection, { title: "Connection", tabId: "connection", activeTab, children: /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Status", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-sm text-green-600", children: [
406
623
  /* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-green-500" }),
407
624
  "Connected"
408
625
  ] }) }) }),
@@ -420,13 +637,13 @@ function SettingsDialog({
420
637
  TabsList,
421
638
  {
422
639
  variant: "default",
423
- className: "gap-2 *:data-[slot=tab-indicator]:duration-0",
424
- children: themeOptions.map((option) => /* @__PURE__ */ jsxs(TabsTab, { value: option.value, children: [
425
- /* @__PURE__ */ jsx(
640
+ className: "gap-1.5 flex-wrap *:data-[slot=tab-indicator]:duration-0",
641
+ children: themeOptions.map((option) => /* @__PURE__ */ jsxs(TabsTab, { value: option.value, className: "text-[11px] px-1 py-0.5 gap-0.5", children: [
642
+ option.icon && /* @__PURE__ */ jsx(
426
643
  HugeiconsIcon,
427
644
  {
428
645
  icon: option.icon,
429
- size: 20,
646
+ size: 13,
430
647
  strokeWidth: 1.5
431
648
  }
432
649
  ),
@@ -436,11 +653,44 @@ function SettingsDialog({
436
653
  )
437
654
  }
438
655
  ) }),
656
+ /* @__PURE__ */ jsx(
657
+ SettingsRow,
658
+ {
659
+ label: "Accent Color",
660
+ children: /* @__PURE__ */ jsx("div", { className: "flex gap-0.5 flex-wrap", children: accentColorOptions.map((option) => {
661
+ const selected = settings.accentColor === option.value;
662
+ return /* @__PURE__ */ jsx(
663
+ "button",
664
+ {
665
+ type: "button",
666
+ onClick: () => handleAccentColorChange(option.value),
667
+ className: cn(
668
+ "flex items-center justify-center rounded-md p-1 transition-all duration-150",
669
+ selected ? "scale-110" : "hover:bg-primary-50 hover:scale-105"
670
+ ),
671
+ children: /* @__PURE__ */ jsx(
672
+ "span",
673
+ {
674
+ className: cn(
675
+ "size-6 rounded-full transition-shadow duration-150",
676
+ selected ? "ring-2 ring-offset-2" : "border-2 border-primary-200"
677
+ ),
678
+ style: {
679
+ backgroundColor: option.accent,
680
+ ...selected ? { "--tw-ring-color": option.accent } : {}
681
+ }
682
+ }
683
+ )
684
+ },
685
+ option.value
686
+ );
687
+ }) })
688
+ }
689
+ ),
439
690
  /* @__PURE__ */ jsx(
440
691
  SettingsRow,
441
692
  {
442
693
  label: "Text Size",
443
- description: "Adjust chat and composer text",
444
694
  children: /* @__PURE__ */ jsx(Tabs, { value: textSize, onValueChange: handleTextSizeChange, children: /* @__PURE__ */ jsx(
445
695
  TabsList,
446
696
  {
@@ -450,24 +700,29 @@ function SettingsDialog({
450
700
  }
451
701
  ) })
452
702
  }
453
- )
703
+ ),
704
+ /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Font", children: /* @__PURE__ */ jsx(Tabs, { value: settings.fontFamily, onValueChange: handleFontFamilyChange, children: /* @__PURE__ */ jsx(TabsList, { variant: "default", className: "gap-1 *:data-[slot=tab-indicator]:duration-0", children: fontFamilyOptions.map((option) => /* @__PURE__ */ jsx(TabsTab, { value: option.value, children: /* @__PURE__ */ jsx("span", { className: "text-xs", style: { fontFamily: option.cssValue }, children: option.label }) }, option.value)) }) }) }),
705
+ /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Density", children: /* @__PURE__ */ jsx(Tabs, { value: settings.density, onValueChange: handleDensityChange, children: /* @__PURE__ */ jsx(TabsList, { variant: "default", className: "gap-1 *:data-[slot=tab-indicator]:duration-0", children: densityOptions.map((option) => /* @__PURE__ */ jsx(TabsTab, { value: option.value, children: /* @__PURE__ */ jsx("span", { className: "text-xs", children: option.label }) }, option.value)) }) }) }),
706
+ /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Bubbles", children: /* @__PURE__ */ jsx(Tabs, { value: settings.bubbleStyle, onValueChange: handleBubbleStyleChange, children: /* @__PURE__ */ jsx(TabsList, { variant: "default", className: "gap-1 *:data-[slot=tab-indicator]:duration-0", children: bubbleStyleOptions.map((option) => /* @__PURE__ */ jsx(TabsTab, { value: option.value, children: /* @__PURE__ */ jsx("span", { className: "text-xs", children: option.label }) }, option.value)) }) }) }),
707
+ /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Chat Width", children: /* @__PURE__ */ jsx(Tabs, { value: settings.chatWidth, onValueChange: handleChatWidthChange, children: /* @__PURE__ */ jsx(TabsList, { variant: "default", className: "gap-1 *:data-[slot=tab-indicator]:duration-0", children: chatWidthOptions.map((option) => /* @__PURE__ */ jsx(TabsTab, { value: option.value, children: /* @__PURE__ */ jsx("span", { className: "text-xs", children: option.label }) }, option.value)) }) }) }),
708
+ /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Sidebar", children: /* @__PURE__ */ jsx(Tabs, { value: settings.sidebarWidth, onValueChange: handleSidebarWidthChange, children: /* @__PURE__ */ jsx(TabsList, { variant: "default", className: "gap-1 *:data-[slot=tab-indicator]:duration-0", children: sidebarWidthOptions.map((option) => /* @__PURE__ */ jsx(TabsTab, { value: option.value, children: /* @__PURE__ */ jsx("span", { className: "text-xs", children: option.label }) }, option.value)) }) }) })
454
709
  ] }),
455
710
  /* @__PURE__ */ jsxs(SettingsSection, { title: "Chat", tabId: "chat", activeTab, children: [
456
- /* @__PURE__ */ jsx(SettingsRow, { label: "Show tool messages", children: /* @__PURE__ */ jsx(
711
+ /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Show tool messages", children: /* @__PURE__ */ jsx(
457
712
  Switch,
458
713
  {
459
714
  checked: settings.showToolMessages,
460
715
  onCheckedChange: (checked) => updateSettings({ showToolMessages: checked })
461
716
  }
462
717
  ) }),
463
- /* @__PURE__ */ jsx(SettingsRow, { label: "Show reasoning blocks", children: /* @__PURE__ */ jsx(
718
+ /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Show reasoning blocks", children: /* @__PURE__ */ jsx(
464
719
  Switch,
465
720
  {
466
721
  checked: settings.showReasoningBlocks,
467
722
  onCheckedChange: (checked) => updateSettings({ showReasoningBlocks: checked })
468
723
  }
469
724
  ) }),
470
- /* @__PURE__ */ jsx(SettingsRow, { label: "Show search sources", children: /* @__PURE__ */ jsx(
725
+ /* @__PURE__ */ jsx(SettingsRow, { inline: true, label: "Show search sources", children: /* @__PURE__ */ jsx(
471
726
  Switch,
472
727
  {
473
728
  checked: settings.showSearchSources,
@@ -477,6 +732,7 @@ function SettingsDialog({
477
732
  /* @__PURE__ */ jsx(
478
733
  SettingsRow,
479
734
  {
735
+ inline: true,
480
736
  label: "Agent Manager (Beta)",
481
737
  description: "Show Agent Manager in sidebar for creating and managing agents",
482
738
  children: /* @__PURE__ */ jsx(
@@ -500,6 +756,31 @@ function SettingsDialog({
500
756
  /* @__PURE__ */ jsx(
501
757
  SettingsRow,
502
758
  {
759
+ inline: true,
760
+ label: "Skills Browser (Beta)",
761
+ description: "Browse and install skills from ClawHub",
762
+ children: /* @__PURE__ */ jsx(
763
+ Switch,
764
+ {
765
+ checked: (() => {
766
+ try {
767
+ return localStorage.getItem("opencami-skills-browser") === "true";
768
+ } catch {
769
+ return false;
770
+ }
771
+ })(),
772
+ onCheckedChange: (checked) => {
773
+ localStorage.setItem("opencami-skills-browser", String(checked));
774
+ window.location.reload();
775
+ }
776
+ }
777
+ )
778
+ }
779
+ ),
780
+ /* @__PURE__ */ jsx(
781
+ SettingsRow,
782
+ {
783
+ inline: true,
503
784
  label: "Cron Jobs Panel (Beta)",
504
785
  description: "Show Cron Jobs in sidebar for managing OpenClaw cron schedules",
505
786
  children: /* @__PURE__ */ jsx(
@@ -523,6 +804,7 @@ function SettingsDialog({
523
804
  /* @__PURE__ */ jsx(
524
805
  SettingsRow,
525
806
  {
807
+ inline: true,
526
808
  label: "Inline File Preview",
527
809
  description: "Make file paths in messages clickable to preview file contents",
528
810
  children: /* @__PURE__ */ jsx(
@@ -539,6 +821,7 @@ function SettingsDialog({
539
821
  personasAvailable ? /* @__PURE__ */ jsx(
540
822
  SettingsRow,
541
823
  {
824
+ inline: true,
542
825
  label: "Persona Picker",
543
826
  description: "Show persona picker in chat (20 personalities)",
544
827
  children: /* @__PURE__ */ jsx(
@@ -552,6 +835,7 @@ function SettingsDialog({
552
835
  ) : /* @__PURE__ */ jsx(
553
836
  SettingsRow,
554
837
  {
838
+ inline: true,
555
839
  label: "Persona Picker",
556
840
  description: "Install the Personas skill to unlock 20 AI personalities",
557
841
  children: /* @__PURE__ */ jsx(Switch, { checked: false, disabled: true })
@@ -572,6 +856,7 @@ function SettingsDialog({
572
856
  /* @__PURE__ */ jsx(
573
857
  SettingsRow,
574
858
  {
859
+ inline: true,
575
860
  label: "Voice Playback",
576
861
  description: "Add a 🔊 button to AI messages for text-to-speech",
577
862
  children: /* @__PURE__ */ jsx(
@@ -586,6 +871,7 @@ function SettingsDialog({
586
871
  /* @__PURE__ */ jsx(
587
872
  SettingsRow,
588
873
  {
874
+ inline: true,
589
875
  label: "TTS Provider",
590
876
  description: "Choose which service generates speech",
591
877
  children: /* @__PURE__ */ jsxs(
@@ -607,6 +893,7 @@ function SettingsDialog({
607
893
  ttsProvider === "openai" && /* @__PURE__ */ jsx(
608
894
  SettingsRow,
609
895
  {
896
+ inline: true,
610
897
  label: "Voice",
611
898
  description: "OpenAI voice selection",
612
899
  children: /* @__PURE__ */ jsx(
@@ -624,6 +911,7 @@ function SettingsDialog({
624
911
  /* @__PURE__ */ jsx(SettingsSection, { title: "Speech-to-Text", tabId: "voice", activeTab, children: /* @__PURE__ */ jsx(
625
912
  SettingsRow,
626
913
  {
914
+ inline: true,
627
915
  label: "STT Provider",
628
916
  description: "Choose which service transcribes your voice",
629
917
  children: /* @__PURE__ */ jsxs(
@@ -651,6 +939,7 @@ function SettingsDialog({
651
939
  /* @__PURE__ */ jsx(
652
940
  SettingsRow,
653
941
  {
942
+ inline: true,
654
943
  label: "Provider",
655
944
  description: "Choose LLM provider for titles & follow-ups",
656
945
  children: /* @__PURE__ */ jsxs(
@@ -679,6 +968,7 @@ function SettingsDialog({
679
968
  /* @__PURE__ */ jsx(
680
969
  SettingsRow,
681
970
  {
971
+ inline: true,
682
972
  label: "Smart session titles",
683
973
  description: "Generate concise titles using AI",
684
974
  children: /* @__PURE__ */ jsx(
@@ -694,6 +984,7 @@ function SettingsDialog({
694
984
  /* @__PURE__ */ jsx(
695
985
  SettingsRow,
696
986
  {
987
+ inline: true,
697
988
  label: "Smart follow-up suggestions",
698
989
  description: "AI-generated contextual follow-ups",
699
990
  children: /* @__PURE__ */ jsx(
@@ -841,7 +1132,7 @@ function SettingsDialog({
841
1132
  ] })
842
1133
  ] })
843
1134
  ] }),
844
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-end", children: /* @__PURE__ */ jsx(DialogClose, { onClick: onClose, children: "Close" }) })
1135
+ /* @__PURE__ */ jsx("div", { className: "mt-2 flex justify-end", children: /* @__PURE__ */ jsx(DialogClose, { onClick: onClose, children: "Close" }) })
845
1136
  ] }) }) });
846
1137
  }
847
1138
  export {