opencami 1.8.8 → 1.8.9
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.
- package/dist/client/assets/{CSPContext-nHSyQniZ.js → CSPContext-DI-5GAnQ.js} +1 -1
- package/dist/client/assets/{DirectionContext-B1cuzwIr.js → DirectionContext-CrIsc5n9.js} +1 -1
- package/dist/client/assets/_sessionKey-B4NZmxf3.js +21 -0
- package/dist/client/assets/agents-bptidK8z.js +2 -0
- package/dist/client/assets/{agents-screen-DpNSh5Ok.js → agents-screen-6qdnPmx2.js} +1 -1
- package/dist/client/assets/bots-BWpbaQ-E.js +2 -0
- package/dist/client/assets/{bots-screen-Qh_IK9hC.js → bots-screen-BTKCOohV.js} +1 -1
- package/dist/client/assets/{button-DdG8c-XQ.js → button-8ab4wOwy.js} +1 -1
- package/dist/client/assets/{composite-Cx-QHT9o.js → composite-B2qsrzf3.js} +1 -1
- package/dist/client/assets/{connect-CSbeSBTn.js → connect-B3_p7C4I.js} +1 -1
- package/dist/client/assets/dashboard-BtClHYpn.js +1 -0
- package/dist/client/assets/{event-Dwf9IDxK.js → event-DG3RKJz8.js} +1 -1
- package/dist/client/assets/{file-explorer-screen-DzDX4HcB.js → file-explorer-screen-Djl8x-8P.js} +1 -1
- package/dist/client/assets/files-CjbCJDgC.js +2 -0
- package/dist/client/assets/{follow-up-suggestions-BYWq-d8P.js → follow-up-suggestions-BSCMXRXh.js} +1 -1
- package/dist/client/assets/{index-BxsgifDH.js → index-BXiha-Vz.js} +1 -1
- package/dist/client/assets/{index-B551ln24.js → index-CtlYu8Ug.js} +1 -1
- package/dist/client/assets/{keyboard-shortcuts-dialog-BX-hH4Wf.js → keyboard-shortcuts-dialog-HAufCn9C.js} +1 -1
- package/dist/client/assets/{main-DBmooBKx.js → main-CQKtcNr3.js} +2 -2
- package/dist/client/assets/{markdown-Bpat4kTr.js → markdown-DFJF-FsV.js} +1 -1
- package/dist/client/assets/memory-DnJOmcwU.js +2 -0
- package/dist/client/assets/{memory-screen-1DgDLyZf.js → memory-screen-Bm4NMAnU.js} +1 -1
- package/dist/client/assets/{menu-ByR1BVmq.js → menu-D26Vmgxl.js} +1 -1
- package/dist/client/assets/{opencami-logo-BV1uPYe6.js → opencami-logo-BSed2Wez.js} +1 -1
- package/dist/client/assets/{popupStateMapping-CGDLUl5Y.js → popupStateMapping-DkI2OCkW.js} +1 -1
- package/dist/client/assets/{proxy-DYrSkM35.js → proxy-CHQ-VCN1.js} +1 -1
- package/dist/client/assets/{react-dSDkXQu6.js → react-WkSlhZJd.js} +1 -1
- package/dist/client/assets/{search-dialog-B3XJLq-O.js → search-dialog-CCl4d0Pi.js} +1 -1
- package/dist/client/assets/{search-sources-badge-CTd0gLuz.js → search-sources-badge-Du8KpUEb.js} +1 -1
- package/dist/client/assets/{session-export-dialog-Cib97JLm.js → session-export-dialog-io9FvLKq.js} +1 -1
- package/dist/client/assets/{settings-dialog-B4NLq1ZS.js → settings-dialog-B93qswor.js} +1 -1
- package/dist/client/assets/skills-BNDGnHwM.js +2 -0
- package/dist/client/assets/{skills-panel-Cj7yHGbX.js → skills-panel-CVh1I-7D.js} +1 -1
- package/dist/client/assets/{switch-kXs1I0oW.js → switch-CSnzINDW.js} +1 -1
- package/dist/client/assets/{tabs-B6GW7TBf.js → tabs-CWfn44FL.js} +1 -1
- package/dist/client/assets/{thinking-DTP9JDQl.js → thinking-BmoLlbFC.js} +1 -1
- package/dist/client/assets/{tooltip-CtHpm-sQ.js → tooltip-CSGMH2t4.js} +1 -1
- package/dist/client/assets/{use-file-explorer-state-C-D2CShe.js → use-file-explorer-state-BYVzjwPA.js} +1 -1
- package/dist/client/assets/{useBaseUiId-Ckx_aJky.js → useBaseUiId-DiwX_3so.js} +1 -1
- package/dist/client/assets/{useCompositeItem-CkvfeGmG.js → useCompositeItem-UPIPwR9H.js} +1 -1
- package/dist/client/assets/{useControlled-8D4PSDAL.js → useControlled-CT2hRlcU.js} +1 -1
- package/dist/client/assets/{useMutation-DckvFKPC.js → useMutation-rx8UH99I.js} +1 -1
- package/dist/client/assets/{useQuery-CtUiG53w.js → useQuery-Boaa6oF3.js} +1 -1
- package/dist/server/assets/{_sessionKey-LV6xK9IM.js → _sessionKey-B6iYeyCS.js} +342 -257
- package/dist/server/assets/{_tanstack-start-manifest_v-qVhiIEVc.js → _tanstack-start-manifest_v-C9chPgNH.js} +1 -1
- package/dist/server/assets/{dashboard-GCKodTiJ.js → dashboard-UYRCu_mQ.js} +19 -3
- package/dist/server/assets/{follow-up-suggestions-CSSc4PDe.js → follow-up-suggestions-mzRQIB0k.js} +2 -2
- package/dist/server/assets/{index-DMKS4aeI.js → index-COElhwGA.js} +1 -1
- package/dist/server/assets/{router-Cr2xCvGA.js → router-BqLGFd4L.js} +3 -3
- package/dist/server/assets/{search-dialog-DR6zBnui.js → search-dialog-CmI7naPN.js} +2 -2
- package/dist/server/assets/{settings-dialog-DEMlCMCP.js → settings-dialog-BZ67gr9N.js} +2 -2
- package/dist/server/assets/{thinking-BpAc3itF.js → thinking-CA8PSwKJ.js} +2 -2
- package/dist/server/server.js +2 -2
- package/package.json +2 -2
- package/dist/client/assets/_sessionKey-CNw4O2rY.js +0 -19
- package/dist/client/assets/agents-C6Ev94B1.js +0 -2
- package/dist/client/assets/bots-B2_u-OmP.js +0 -2
- package/dist/client/assets/dashboard-DA1fTRcH.js +0 -1
- package/dist/client/assets/files-PsZnGOUx.js +0 -2
- package/dist/client/assets/memory-Bs8hOoEv.js +0 -2
- package/dist/client/assets/skills-pueagQNc.js +0 -2
|
@@ -19,7 +19,7 @@ import { u as useChatSettings$1 } from "./index-BEWnDAH6.js";
|
|
|
19
19
|
import { createPortal } from "react-dom";
|
|
20
20
|
import { create } from "zustand";
|
|
21
21
|
import { persist } from "zustand/middleware";
|
|
22
|
-
import { a as Route } from "./router-
|
|
22
|
+
import { a as Route } from "./router-BqLGFd4L.js";
|
|
23
23
|
function deriveFriendlyIdFromKey(key) {
|
|
24
24
|
if (!key) return "main";
|
|
25
25
|
const trimmed = key.trim();
|
|
@@ -1681,7 +1681,7 @@ function areSidebarSessionsEqual(prev, next) {
|
|
|
1681
1681
|
return true;
|
|
1682
1682
|
}
|
|
1683
1683
|
const SettingsDialog = lazy(
|
|
1684
|
-
() => import("./settings-dialog-
|
|
1684
|
+
() => import("./settings-dialog-BZ67gr9N.js").then((m) => ({ default: m.SettingsDialog }))
|
|
1685
1685
|
);
|
|
1686
1686
|
const SessionExportDialog = lazy(
|
|
1687
1687
|
() => import("./session-export-dialog-C53RRAah.js").then((m) => ({
|
|
@@ -2828,7 +2828,7 @@ function Tool({ toolPart, defaultOpen = false }) {
|
|
|
2828
2828
|
] }) });
|
|
2829
2829
|
}
|
|
2830
2830
|
const Thinking = lazy(
|
|
2831
|
-
() => import("./thinking-
|
|
2831
|
+
() => import("./thinking-CA8PSwKJ.js").then((m) => ({
|
|
2832
2832
|
default: m.Thinking
|
|
2833
2833
|
}))
|
|
2834
2834
|
);
|
|
@@ -3469,7 +3469,7 @@ function TypingIndicator({ className }) {
|
|
|
3469
3469
|
] });
|
|
3470
3470
|
}
|
|
3471
3471
|
const FollowUpSuggestions = lazy(
|
|
3472
|
-
() => import("./follow-up-suggestions-
|
|
3472
|
+
() => import("./follow-up-suggestions-mzRQIB0k.js").then((m) => ({
|
|
3473
3473
|
default: m.FollowUpSuggestions
|
|
3474
3474
|
}))
|
|
3475
3475
|
);
|
|
@@ -3783,6 +3783,120 @@ const MemoizedChatMessageList = memo(
|
|
|
3783
3783
|
ChatMessageListComponent,
|
|
3784
3784
|
areChatMessageListEqual
|
|
3785
3785
|
);
|
|
3786
|
+
const useThinkingLevelStore = create()(
|
|
3787
|
+
persist(
|
|
3788
|
+
(set) => ({
|
|
3789
|
+
level: "low",
|
|
3790
|
+
setLevel: (level) => set({ level })
|
|
3791
|
+
}),
|
|
3792
|
+
{ name: "thinking-level" }
|
|
3793
|
+
)
|
|
3794
|
+
);
|
|
3795
|
+
function useThinkingLevel() {
|
|
3796
|
+
const level = useThinkingLevelStore((state) => state.level);
|
|
3797
|
+
const setLevel = useThinkingLevelStore((state) => state.setLevel);
|
|
3798
|
+
return { level, setLevel };
|
|
3799
|
+
}
|
|
3800
|
+
const THINKING_OPTIONS = [
|
|
3801
|
+
{ value: "off", label: "Off", description: "No reasoning", shortLabel: "Off" },
|
|
3802
|
+
{ value: "low", label: "Low", description: "Think", shortLabel: "Low" },
|
|
3803
|
+
{ value: "medium", label: "Medium", description: "Think harder", shortLabel: "Medium" },
|
|
3804
|
+
{ value: "high", label: "High", description: "Ultrathink", shortLabel: "High" }
|
|
3805
|
+
];
|
|
3806
|
+
function ThinkingLevelSelector({ className }) {
|
|
3807
|
+
const { level, setLevel } = useThinkingLevel();
|
|
3808
|
+
const current = THINKING_OPTIONS.find((option) => option.value === level) ?? THINKING_OPTIONS[1];
|
|
3809
|
+
return /* @__PURE__ */ jsxs(MenuRoot, { children: [
|
|
3810
|
+
/* @__PURE__ */ jsxs(
|
|
3811
|
+
MenuTrigger,
|
|
3812
|
+
{
|
|
3813
|
+
className: cn(
|
|
3814
|
+
"inline-flex h-7 items-center gap-2 rounded-md px-2 text-xs font-[450] text-primary-600 hover:text-primary-900 hover:bg-primary-100",
|
|
3815
|
+
className
|
|
3816
|
+
),
|
|
3817
|
+
children: [
|
|
3818
|
+
/* @__PURE__ */ jsx(
|
|
3819
|
+
HugeiconsIcon,
|
|
3820
|
+
{
|
|
3821
|
+
icon: AiBrain01Icon,
|
|
3822
|
+
size: 20,
|
|
3823
|
+
strokeWidth: 1.5,
|
|
3824
|
+
className: cn(level === "off" ? "text-primary-400" : "text-primary-700")
|
|
3825
|
+
}
|
|
3826
|
+
),
|
|
3827
|
+
/* @__PURE__ */ jsx("span", { className: "text-pretty", children: current.shortLabel })
|
|
3828
|
+
]
|
|
3829
|
+
}
|
|
3830
|
+
),
|
|
3831
|
+
/* @__PURE__ */ jsx(MenuContent, { side: "top", align: "start", className: "min-w-[190px]", children: THINKING_OPTIONS.map((option) => /* @__PURE__ */ jsxs(
|
|
3832
|
+
MenuItem,
|
|
3833
|
+
{
|
|
3834
|
+
onClick: () => setLevel(option.value),
|
|
3835
|
+
className: "justify-between",
|
|
3836
|
+
children: [
|
|
3837
|
+
/* @__PURE__ */ jsxs("span", { className: "flex flex-col text-pretty", children: [
|
|
3838
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-primary-900", children: option.label }),
|
|
3839
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-primary-500", children: option.description })
|
|
3840
|
+
] }),
|
|
3841
|
+
level === option.value && /* @__PURE__ */ jsx(
|
|
3842
|
+
HugeiconsIcon,
|
|
3843
|
+
{
|
|
3844
|
+
icon: Tick02Icon,
|
|
3845
|
+
size: 20,
|
|
3846
|
+
strokeWidth: 1.5,
|
|
3847
|
+
className: "text-primary-600"
|
|
3848
|
+
}
|
|
3849
|
+
)
|
|
3850
|
+
]
|
|
3851
|
+
},
|
|
3852
|
+
option.value
|
|
3853
|
+
)) })
|
|
3854
|
+
] });
|
|
3855
|
+
}
|
|
3856
|
+
function SlashCommandMenuComponent({
|
|
3857
|
+
commands,
|
|
3858
|
+
selectedIndex,
|
|
3859
|
+
onSelect,
|
|
3860
|
+
className
|
|
3861
|
+
}) {
|
|
3862
|
+
if (commands.length === 0) return null;
|
|
3863
|
+
return /* @__PURE__ */ jsx(
|
|
3864
|
+
"div",
|
|
3865
|
+
{
|
|
3866
|
+
className: cn(
|
|
3867
|
+
"absolute left-2 right-2 md:left-5 md:right-5 bottom-full mb-2 z-20 rounded-xl border border-white/10 bg-neutral-900/95 shadow-2xl backdrop-blur-sm overflow-hidden",
|
|
3868
|
+
className
|
|
3869
|
+
),
|
|
3870
|
+
role: "listbox",
|
|
3871
|
+
"aria-label": "Slash commands",
|
|
3872
|
+
children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: commands.map((item, index) => {
|
|
3873
|
+
const active = index === selectedIndex;
|
|
3874
|
+
return /* @__PURE__ */ jsx(
|
|
3875
|
+
"button",
|
|
3876
|
+
{
|
|
3877
|
+
type: "button",
|
|
3878
|
+
role: "option",
|
|
3879
|
+
"aria-selected": active,
|
|
3880
|
+
onMouseDown: (event) => {
|
|
3881
|
+
event.preventDefault();
|
|
3882
|
+
onSelect(item);
|
|
3883
|
+
},
|
|
3884
|
+
className: cn(
|
|
3885
|
+
"w-full rounded-md px-3 py-2 text-left transition-colors",
|
|
3886
|
+
active ? "bg-neutral-800" : "hover:bg-neutral-800/80"
|
|
3887
|
+
),
|
|
3888
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
3889
|
+
/* @__PURE__ */ jsx("code", { className: "min-w-[90px] font-mono text-xs text-primary-300", children: item.command }),
|
|
3890
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-neutral-300", children: item.description })
|
|
3891
|
+
] })
|
|
3892
|
+
},
|
|
3893
|
+
item.command
|
|
3894
|
+
);
|
|
3895
|
+
}) })
|
|
3896
|
+
}
|
|
3897
|
+
);
|
|
3898
|
+
}
|
|
3899
|
+
const SlashCommandMenu = memo(SlashCommandMenuComponent);
|
|
3786
3900
|
const PromptInputContext = createContext({
|
|
3787
3901
|
isLoading: false,
|
|
3788
3902
|
value: "",
|
|
@@ -4540,120 +4654,6 @@ function AttachmentPreviewList({
|
|
|
4540
4654
|
attachment.id
|
|
4541
4655
|
)) });
|
|
4542
4656
|
}
|
|
4543
|
-
function SlashCommandMenuComponent({
|
|
4544
|
-
commands,
|
|
4545
|
-
selectedIndex,
|
|
4546
|
-
onSelect,
|
|
4547
|
-
className
|
|
4548
|
-
}) {
|
|
4549
|
-
if (commands.length === 0) return null;
|
|
4550
|
-
return /* @__PURE__ */ jsx(
|
|
4551
|
-
"div",
|
|
4552
|
-
{
|
|
4553
|
-
className: cn(
|
|
4554
|
-
"absolute left-2 right-2 md:left-5 md:right-5 bottom-full mb-2 z-20 rounded-xl border border-white/10 bg-neutral-900/95 shadow-2xl backdrop-blur-sm overflow-hidden",
|
|
4555
|
-
className
|
|
4556
|
-
),
|
|
4557
|
-
role: "listbox",
|
|
4558
|
-
"aria-label": "Slash commands",
|
|
4559
|
-
children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: commands.map((item, index) => {
|
|
4560
|
-
const active = index === selectedIndex;
|
|
4561
|
-
return /* @__PURE__ */ jsx(
|
|
4562
|
-
"button",
|
|
4563
|
-
{
|
|
4564
|
-
type: "button",
|
|
4565
|
-
role: "option",
|
|
4566
|
-
"aria-selected": active,
|
|
4567
|
-
onMouseDown: (event) => {
|
|
4568
|
-
event.preventDefault();
|
|
4569
|
-
onSelect(item);
|
|
4570
|
-
},
|
|
4571
|
-
className: cn(
|
|
4572
|
-
"w-full rounded-md px-3 py-2 text-left transition-colors",
|
|
4573
|
-
active ? "bg-neutral-800" : "hover:bg-neutral-800/80"
|
|
4574
|
-
),
|
|
4575
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
4576
|
-
/* @__PURE__ */ jsx("code", { className: "min-w-[90px] font-mono text-xs text-primary-300", children: item.command }),
|
|
4577
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-neutral-300", children: item.description })
|
|
4578
|
-
] })
|
|
4579
|
-
},
|
|
4580
|
-
item.command
|
|
4581
|
-
);
|
|
4582
|
-
}) })
|
|
4583
|
-
}
|
|
4584
|
-
);
|
|
4585
|
-
}
|
|
4586
|
-
const SlashCommandMenu = memo(SlashCommandMenuComponent);
|
|
4587
|
-
const useThinkingLevelStore = create()(
|
|
4588
|
-
persist(
|
|
4589
|
-
(set) => ({
|
|
4590
|
-
level: "low",
|
|
4591
|
-
setLevel: (level) => set({ level })
|
|
4592
|
-
}),
|
|
4593
|
-
{ name: "thinking-level" }
|
|
4594
|
-
)
|
|
4595
|
-
);
|
|
4596
|
-
function useThinkingLevel() {
|
|
4597
|
-
const level = useThinkingLevelStore((state) => state.level);
|
|
4598
|
-
const setLevel = useThinkingLevelStore((state) => state.setLevel);
|
|
4599
|
-
return { level, setLevel };
|
|
4600
|
-
}
|
|
4601
|
-
const THINKING_OPTIONS = [
|
|
4602
|
-
{ value: "off", label: "Off", description: "No reasoning", shortLabel: "Off" },
|
|
4603
|
-
{ value: "low", label: "Low", description: "Think", shortLabel: "Low" },
|
|
4604
|
-
{ value: "medium", label: "Medium", description: "Think harder", shortLabel: "Medium" },
|
|
4605
|
-
{ value: "high", label: "High", description: "Ultrathink", shortLabel: "High" }
|
|
4606
|
-
];
|
|
4607
|
-
function ThinkingLevelSelector({ className }) {
|
|
4608
|
-
const { level, setLevel } = useThinkingLevel();
|
|
4609
|
-
const current = THINKING_OPTIONS.find((option) => option.value === level) ?? THINKING_OPTIONS[1];
|
|
4610
|
-
return /* @__PURE__ */ jsxs(MenuRoot, { children: [
|
|
4611
|
-
/* @__PURE__ */ jsxs(
|
|
4612
|
-
MenuTrigger,
|
|
4613
|
-
{
|
|
4614
|
-
className: cn(
|
|
4615
|
-
"inline-flex h-7 items-center gap-2 rounded-md px-2 text-xs font-[450] text-primary-600 hover:text-primary-900 hover:bg-primary-100",
|
|
4616
|
-
className
|
|
4617
|
-
),
|
|
4618
|
-
children: [
|
|
4619
|
-
/* @__PURE__ */ jsx(
|
|
4620
|
-
HugeiconsIcon,
|
|
4621
|
-
{
|
|
4622
|
-
icon: AiBrain01Icon,
|
|
4623
|
-
size: 20,
|
|
4624
|
-
strokeWidth: 1.5,
|
|
4625
|
-
className: cn(level === "off" ? "text-primary-400" : "text-primary-700")
|
|
4626
|
-
}
|
|
4627
|
-
),
|
|
4628
|
-
/* @__PURE__ */ jsx("span", { className: "text-pretty", children: current.shortLabel })
|
|
4629
|
-
]
|
|
4630
|
-
}
|
|
4631
|
-
),
|
|
4632
|
-
/* @__PURE__ */ jsx(MenuContent, { side: "top", align: "start", className: "min-w-[190px]", children: THINKING_OPTIONS.map((option) => /* @__PURE__ */ jsxs(
|
|
4633
|
-
MenuItem,
|
|
4634
|
-
{
|
|
4635
|
-
onClick: () => setLevel(option.value),
|
|
4636
|
-
className: "justify-between",
|
|
4637
|
-
children: [
|
|
4638
|
-
/* @__PURE__ */ jsxs("span", { className: "flex flex-col text-pretty", children: [
|
|
4639
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-primary-900", children: option.label }),
|
|
4640
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-primary-500", children: option.description })
|
|
4641
|
-
] }),
|
|
4642
|
-
level === option.value && /* @__PURE__ */ jsx(
|
|
4643
|
-
HugeiconsIcon,
|
|
4644
|
-
{
|
|
4645
|
-
icon: Tick02Icon,
|
|
4646
|
-
size: 20,
|
|
4647
|
-
strokeWidth: 1.5,
|
|
4648
|
-
className: "text-primary-600"
|
|
4649
|
-
}
|
|
4650
|
-
)
|
|
4651
|
-
]
|
|
4652
|
-
},
|
|
4653
|
-
option.value
|
|
4654
|
-
)) })
|
|
4655
|
-
] });
|
|
4656
|
-
}
|
|
4657
4657
|
const FALLBACK_SLASH_COMMANDS = [
|
|
4658
4658
|
// Model aliases
|
|
4659
4659
|
{ command: "/haiku", description: "Switch to Claude Haiku 4.5" },
|
|
@@ -4677,12 +4677,21 @@ const FALLBACK_SLASH_COMMANDS = [
|
|
|
4677
4677
|
{ command: "/status", description: "Show session status & usage" },
|
|
4678
4678
|
{ command: "/whoami", description: "Show your sender ID" },
|
|
4679
4679
|
{ command: "/context", description: "Show context window details" },
|
|
4680
|
-
{
|
|
4680
|
+
{
|
|
4681
|
+
command: "/usage",
|
|
4682
|
+
description: "Toggle usage footer (off/tokens/full/cost)"
|
|
4683
|
+
},
|
|
4681
4684
|
// Directives
|
|
4682
|
-
{
|
|
4685
|
+
{
|
|
4686
|
+
command: "/think",
|
|
4687
|
+
description: "Set thinking level (off/low/medium/high)"
|
|
4688
|
+
},
|
|
4683
4689
|
{ command: "/reasoning", description: "Toggle reasoning (on/off/stream)" },
|
|
4684
4690
|
{ command: "/verbose", description: "Toggle verbose mode (on/full/off)" },
|
|
4685
|
-
{
|
|
4691
|
+
{
|
|
4692
|
+
command: "/elevated",
|
|
4693
|
+
description: "Toggle elevated permissions (on/off/ask)"
|
|
4694
|
+
},
|
|
4686
4695
|
{ command: "/exec", description: "Configure exec settings" },
|
|
4687
4696
|
{ command: "/queue", description: "Show/configure message queue" },
|
|
4688
4697
|
// TTS
|
|
@@ -4699,13 +4708,28 @@ const FALLBACK_SLASH_COMMANDS = [
|
|
|
4699
4708
|
{ command: "/debug", description: "Runtime overrides (owner-only)" },
|
|
4700
4709
|
{ command: "/send", description: "Toggle message sending (on/off)" },
|
|
4701
4710
|
{ command: "/restart", description: "Restart gateway" },
|
|
4702
|
-
{
|
|
4711
|
+
{
|
|
4712
|
+
command: "/activation",
|
|
4713
|
+
description: "Set activation mode (mention/always)"
|
|
4714
|
+
},
|
|
4703
4715
|
// Channels
|
|
4704
4716
|
{ command: "/dock-telegram", description: "Switch replies to Telegram" },
|
|
4705
4717
|
{ command: "/dock-discord", description: "Switch replies to Discord" },
|
|
4706
4718
|
// Other
|
|
4707
4719
|
{ command: "/bash", description: "Run host shell command" }
|
|
4708
4720
|
];
|
|
4721
|
+
function escapeRegExp(value) {
|
|
4722
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4723
|
+
}
|
|
4724
|
+
function removeUploadedFilePrompt(value, uploadedPath) {
|
|
4725
|
+
const escapedPath = escapeRegExp(uploadedPath);
|
|
4726
|
+
const uploadedFileBlockRegex = new RegExp(
|
|
4727
|
+
`(?:^|\\n\\n)📎 Uploaded file: ${escapedPath}\\n\\nPlease analyze this file\\.(?=\\n\\n|$)`
|
|
4728
|
+
);
|
|
4729
|
+
return value.replace(uploadedFileBlockRegex, (match, offset) => {
|
|
4730
|
+
return offset === 0 ? "" : "\n\n";
|
|
4731
|
+
}).trim();
|
|
4732
|
+
}
|
|
4709
4733
|
function ChatComposerComponent({
|
|
4710
4734
|
onSubmit,
|
|
4711
4735
|
isLoading,
|
|
@@ -4729,12 +4753,20 @@ function ChatComposerComponent({
|
|
|
4729
4753
|
const sttAbortControllerRef = useRef(null);
|
|
4730
4754
|
const webSpeechRef = useRef(null);
|
|
4731
4755
|
const promptRef = useRef(null);
|
|
4732
|
-
const showSlashCommands = useMemo(
|
|
4733
|
-
|
|
4756
|
+
const showSlashCommands = useMemo(
|
|
4757
|
+
() => /^\/\S*$/.test(value) && !slashMenuDismissed,
|
|
4758
|
+
[value, slashMenuDismissed]
|
|
4759
|
+
);
|
|
4760
|
+
const slashQuery = useMemo(
|
|
4761
|
+
() => showSlashCommands ? value.slice(1).toLowerCase() : "",
|
|
4762
|
+
[showSlashCommands, value]
|
|
4763
|
+
);
|
|
4734
4764
|
const filteredSlashCommands = useMemo(() => {
|
|
4735
4765
|
if (!showSlashCommands) return [];
|
|
4736
4766
|
if (!slashQuery) return FALLBACK_SLASH_COMMANDS;
|
|
4737
|
-
return FALLBACK_SLASH_COMMANDS.filter(
|
|
4767
|
+
return FALLBACK_SLASH_COMMANDS.filter(
|
|
4768
|
+
(item) => item.command.slice(1).toLowerCase().startsWith(slashQuery)
|
|
4769
|
+
);
|
|
4738
4770
|
}, [showSlashCommands, slashQuery]);
|
|
4739
4771
|
const setPromptRef = useCallback(
|
|
4740
4772
|
(element) => {
|
|
@@ -4783,66 +4815,86 @@ ${template}`;
|
|
|
4783
4815
|
body: JSON.stringify({ path: "/uploads" })
|
|
4784
4816
|
});
|
|
4785
4817
|
}, []);
|
|
4786
|
-
const uploadAttachmentFile = useCallback(
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
try {
|
|
4799
|
-
await ensureUploadsDirectory();
|
|
4800
|
-
const formData = new FormData();
|
|
4801
|
-
formData.append("path", "/uploads");
|
|
4802
|
-
formData.append("file", file);
|
|
4803
|
-
const response = await fetch("/api/files/upload", {
|
|
4804
|
-
method: "POST",
|
|
4805
|
-
body: formData
|
|
4806
|
-
});
|
|
4807
|
-
if (!response.ok) {
|
|
4808
|
-
const message = await response.text();
|
|
4809
|
-
throw new Error(message || "File upload failed");
|
|
4818
|
+
const uploadAttachmentFile = useCallback(
|
|
4819
|
+
async (file) => {
|
|
4820
|
+
const id = crypto.randomUUID();
|
|
4821
|
+
if (!isAcceptedNonImage(file)) {
|
|
4822
|
+
return {
|
|
4823
|
+
id,
|
|
4824
|
+
file,
|
|
4825
|
+
preview: null,
|
|
4826
|
+
type: "file",
|
|
4827
|
+
base64: null,
|
|
4828
|
+
error: "Unsupported file type for upload."
|
|
4829
|
+
};
|
|
4810
4830
|
}
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4831
|
+
try {
|
|
4832
|
+
await ensureUploadsDirectory();
|
|
4833
|
+
const formData = new FormData();
|
|
4834
|
+
formData.append("path", "/uploads");
|
|
4835
|
+
formData.append("file", file);
|
|
4836
|
+
const response = await fetch("/api/files/upload", {
|
|
4837
|
+
method: "POST",
|
|
4838
|
+
body: formData
|
|
4839
|
+
});
|
|
4840
|
+
if (!response.ok) {
|
|
4841
|
+
const message = await response.text();
|
|
4842
|
+
throw new Error(message || "File upload failed");
|
|
4843
|
+
}
|
|
4844
|
+
const data = await response.json();
|
|
4845
|
+
const uploadedPath = data.files?.[0]?.path;
|
|
4846
|
+
if (!uploadedPath) {
|
|
4847
|
+
throw new Error("Upload succeeded but no path was returned");
|
|
4848
|
+
}
|
|
4849
|
+
appendUploadedFilePrompt(uploadedPath);
|
|
4850
|
+
return {
|
|
4851
|
+
id,
|
|
4852
|
+
file,
|
|
4853
|
+
preview: null,
|
|
4854
|
+
type: "file",
|
|
4855
|
+
base64: null,
|
|
4856
|
+
uploadedPath
|
|
4857
|
+
};
|
|
4858
|
+
} catch (err) {
|
|
4859
|
+
return {
|
|
4860
|
+
id,
|
|
4861
|
+
file,
|
|
4862
|
+
preview: null,
|
|
4863
|
+
type: "file",
|
|
4864
|
+
base64: null,
|
|
4865
|
+
error: err instanceof Error ? err.message : "File upload failed"
|
|
4866
|
+
};
|
|
4815
4867
|
}
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
error: err instanceof Error ? err.message : "File upload failed"
|
|
4833
|
-
};
|
|
4834
|
-
}
|
|
4835
|
-
}, [appendUploadedFilePrompt, ensureUploadsDirectory]);
|
|
4836
|
-
const handleFilesSelect = useCallback(async (files) => {
|
|
4837
|
-
if (files.length === 0) return;
|
|
4838
|
-
const nextAttachments = await Promise.all(
|
|
4839
|
-
files.map((file) => isAcceptedImage(file) ? createAttachmentFromFile(file) : uploadAttachmentFile(file))
|
|
4840
|
-
);
|
|
4841
|
-
setAttachments((prev) => [...prev, ...nextAttachments]);
|
|
4842
|
-
focusPrompt();
|
|
4843
|
-
}, [focusPrompt, uploadAttachmentFile]);
|
|
4868
|
+
},
|
|
4869
|
+
[appendUploadedFilePrompt, ensureUploadsDirectory]
|
|
4870
|
+
);
|
|
4871
|
+
const handleFilesSelect = useCallback(
|
|
4872
|
+
async (files) => {
|
|
4873
|
+
if (files.length === 0) return;
|
|
4874
|
+
const nextAttachments = await Promise.all(
|
|
4875
|
+
files.map(
|
|
4876
|
+
(file) => isAcceptedImage(file) ? createAttachmentFromFile(file) : uploadAttachmentFile(file)
|
|
4877
|
+
)
|
|
4878
|
+
);
|
|
4879
|
+
setAttachments((prev) => [...prev, ...nextAttachments]);
|
|
4880
|
+
focusPrompt();
|
|
4881
|
+
},
|
|
4882
|
+
[focusPrompt, uploadAttachmentFile]
|
|
4883
|
+
);
|
|
4844
4884
|
const handleRemoveAttachment = useCallback((id) => {
|
|
4845
|
-
|
|
4885
|
+
let removedUploadedPath;
|
|
4886
|
+
setAttachments((prev) => {
|
|
4887
|
+
const attachmentToRemove = prev.find((attachment) => attachment.id === id);
|
|
4888
|
+
if (attachmentToRemove?.uploadedPath) {
|
|
4889
|
+
removedUploadedPath = attachmentToRemove.uploadedPath;
|
|
4890
|
+
}
|
|
4891
|
+
return prev.filter((attachment) => attachment.id !== id);
|
|
4892
|
+
});
|
|
4893
|
+
if (removedUploadedPath) {
|
|
4894
|
+
setValue(
|
|
4895
|
+
(currentValue) => removeUploadedFilePrompt(currentValue, removedUploadedPath)
|
|
4896
|
+
);
|
|
4897
|
+
}
|
|
4846
4898
|
}, []);
|
|
4847
4899
|
const handleDragOver = useCallback((event) => {
|
|
4848
4900
|
const hasFiles = Array.from(event.dataTransfer.types).includes("Files");
|
|
@@ -4857,13 +4909,16 @@ ${template}`;
|
|
|
4857
4909
|
if (nextTarget && event.currentTarget.contains(nextTarget)) return;
|
|
4858
4910
|
setIsDragActive(false);
|
|
4859
4911
|
}, []);
|
|
4860
|
-
const handleDrop = useCallback(
|
|
4861
|
-
event
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4912
|
+
const handleDrop = useCallback(
|
|
4913
|
+
async (event) => {
|
|
4914
|
+
event.preventDefault();
|
|
4915
|
+
setIsDragActive(false);
|
|
4916
|
+
const files = Array.from(event.dataTransfer.files);
|
|
4917
|
+
if (files.length === 0) return;
|
|
4918
|
+
await handleFilesSelect(files);
|
|
4919
|
+
},
|
|
4920
|
+
[handleFilesSelect]
|
|
4921
|
+
);
|
|
4867
4922
|
const setComposerValue = useCallback(
|
|
4868
4923
|
(nextValue) => {
|
|
4869
4924
|
setValue(nextValue);
|
|
@@ -4890,14 +4945,22 @@ ${template}`;
|
|
|
4890
4945
|
const handleSubmit = useCallback(() => {
|
|
4891
4946
|
if (disabled) return;
|
|
4892
4947
|
if (showSlashCommands && filteredSlashCommands.length > 0) {
|
|
4893
|
-
const nextIndex = Math.min(
|
|
4948
|
+
const nextIndex = Math.min(
|
|
4949
|
+
selectedCommandIndex,
|
|
4950
|
+
filteredSlashCommands.length - 1
|
|
4951
|
+
);
|
|
4894
4952
|
selectSlashCommand(filteredSlashCommands[nextIndex]);
|
|
4895
4953
|
return;
|
|
4896
4954
|
}
|
|
4897
4955
|
const body = value.trim();
|
|
4898
4956
|
const validAttachments2 = attachments.filter((a) => !a.error && a.base64);
|
|
4899
4957
|
if (body.length === 0 && validAttachments2.length === 0) return;
|
|
4900
|
-
onSubmit(body, {
|
|
4958
|
+
onSubmit(body, {
|
|
4959
|
+
reset,
|
|
4960
|
+
setValue: setComposerValue,
|
|
4961
|
+
model: selectedModel || void 0,
|
|
4962
|
+
attachments: validAttachments2
|
|
4963
|
+
});
|
|
4901
4964
|
focusPrompt();
|
|
4902
4965
|
}, [
|
|
4903
4966
|
disabled,
|
|
@@ -4915,7 +4978,12 @@ ${template}`;
|
|
|
4915
4978
|
]);
|
|
4916
4979
|
const handlePersonaSelect = useCallback(
|
|
4917
4980
|
(command) => {
|
|
4918
|
-
onSubmit(command, {
|
|
4981
|
+
onSubmit(command, {
|
|
4982
|
+
reset,
|
|
4983
|
+
setValue: setComposerValue,
|
|
4984
|
+
model: selectedModel || void 0,
|
|
4985
|
+
attachments: []
|
|
4986
|
+
});
|
|
4919
4987
|
focusPrompt();
|
|
4920
4988
|
},
|
|
4921
4989
|
[focusPrompt, onSubmit, reset, setComposerValue, selectedModel]
|
|
@@ -4932,21 +5000,33 @@ ${template}`;
|
|
|
4932
5000
|
if (filteredSlashCommands.length === 0) return;
|
|
4933
5001
|
if (event.key === "ArrowDown") {
|
|
4934
5002
|
event.preventDefault();
|
|
4935
|
-
setSelectedCommandIndex(
|
|
5003
|
+
setSelectedCommandIndex(
|
|
5004
|
+
(prev) => (prev + 1) % filteredSlashCommands.length
|
|
5005
|
+
);
|
|
4936
5006
|
return;
|
|
4937
5007
|
}
|
|
4938
5008
|
if (event.key === "ArrowUp") {
|
|
4939
5009
|
event.preventDefault();
|
|
4940
|
-
setSelectedCommandIndex(
|
|
5010
|
+
setSelectedCommandIndex(
|
|
5011
|
+
(prev) => (prev - 1 + filteredSlashCommands.length) % filteredSlashCommands.length
|
|
5012
|
+
);
|
|
4941
5013
|
return;
|
|
4942
5014
|
}
|
|
4943
5015
|
if (event.key === "Tab") {
|
|
4944
5016
|
event.preventDefault();
|
|
4945
|
-
const nextIndex = Math.min(
|
|
5017
|
+
const nextIndex = Math.min(
|
|
5018
|
+
selectedCommandIndex,
|
|
5019
|
+
filteredSlashCommands.length - 1
|
|
5020
|
+
);
|
|
4946
5021
|
selectSlashCommand(filteredSlashCommands[nextIndex]);
|
|
4947
5022
|
}
|
|
4948
5023
|
},
|
|
4949
|
-
[
|
|
5024
|
+
[
|
|
5025
|
+
showSlashCommands,
|
|
5026
|
+
filteredSlashCommands,
|
|
5027
|
+
selectedCommandIndex,
|
|
5028
|
+
selectSlashCommand
|
|
5029
|
+
]
|
|
4950
5030
|
);
|
|
4951
5031
|
useEffect(() => {
|
|
4952
5032
|
return () => {
|
|
@@ -5027,7 +5107,9 @@ ${template}`;
|
|
|
5027
5107
|
setIsRecording(false);
|
|
5028
5108
|
setRecordingTime(0);
|
|
5029
5109
|
if (recordingTimerRef.current) clearInterval(recordingTimerRef.current);
|
|
5030
|
-
showMicError(
|
|
5110
|
+
showMicError(
|
|
5111
|
+
"Speech recognition failed. Try the Browser provider again or switch providers in Settings."
|
|
5112
|
+
);
|
|
5031
5113
|
};
|
|
5032
5114
|
recognition.start();
|
|
5033
5115
|
return;
|
|
@@ -5043,17 +5125,27 @@ ${template}`;
|
|
|
5043
5125
|
};
|
|
5044
5126
|
recorder.onstop = async () => {
|
|
5045
5127
|
stream.getTracks().forEach((t) => t.stop());
|
|
5046
|
-
const audioBlob = new Blob(recordingChunksRef.current, {
|
|
5128
|
+
const audioBlob = new Blob(recordingChunksRef.current, {
|
|
5129
|
+
type: mimeType
|
|
5130
|
+
});
|
|
5047
5131
|
if (audioBlob.size === 0) return;
|
|
5048
5132
|
setSttLoading(true);
|
|
5049
5133
|
try {
|
|
5050
5134
|
const formData = new FormData();
|
|
5051
|
-
formData.append(
|
|
5135
|
+
formData.append(
|
|
5136
|
+
"audio",
|
|
5137
|
+
audioBlob,
|
|
5138
|
+
`recording.${mimeType === "audio/webm" ? "webm" : "mp4"}`
|
|
5139
|
+
);
|
|
5052
5140
|
if (provider !== "auto") formData.append("provider", provider);
|
|
5053
5141
|
sttAbortControllerRef.current?.abort();
|
|
5054
5142
|
const controller = new AbortController();
|
|
5055
5143
|
sttAbortControllerRef.current = controller;
|
|
5056
|
-
const res = await fetch("/api/stt", {
|
|
5144
|
+
const res = await fetch("/api/stt", {
|
|
5145
|
+
method: "POST",
|
|
5146
|
+
body: formData,
|
|
5147
|
+
signal: controller.signal
|
|
5148
|
+
});
|
|
5057
5149
|
const data = await res.json();
|
|
5058
5150
|
if (data.ok && data.text) {
|
|
5059
5151
|
setMicError(null);
|
|
@@ -5061,7 +5153,9 @@ ${template}`;
|
|
|
5061
5153
|
focusPrompt();
|
|
5062
5154
|
} else if (!data.ok) {
|
|
5063
5155
|
console.warn("STT failed:", data.error);
|
|
5064
|
-
showMicError(
|
|
5156
|
+
showMicError(
|
|
5157
|
+
data.error || "Speech-to-text failed. Try the Browser provider in Settings."
|
|
5158
|
+
);
|
|
5065
5159
|
}
|
|
5066
5160
|
} catch (err) {
|
|
5067
5161
|
if (err instanceof Error && err.name === "AbortError") return;
|
|
@@ -5087,14 +5181,22 @@ ${template}`;
|
|
|
5087
5181
|
const msg = err instanceof Error ? err.message : String(err);
|
|
5088
5182
|
if (msg.includes("NotAllowedError") || msg.includes("Permission")) {
|
|
5089
5183
|
try {
|
|
5090
|
-
const status = await navigator.permissions.query({
|
|
5184
|
+
const status = await navigator.permissions.query({
|
|
5185
|
+
name: "microphone"
|
|
5186
|
+
});
|
|
5091
5187
|
if (status.state === "denied") {
|
|
5092
|
-
showMicError(
|
|
5188
|
+
showMicError(
|
|
5189
|
+
"Microphone access is blocked. Please enable it in your browser/app settings."
|
|
5190
|
+
);
|
|
5093
5191
|
} else {
|
|
5094
|
-
showMicError(
|
|
5192
|
+
showMicError(
|
|
5193
|
+
"Microphone permission was not granted. Please try again and allow access when prompted."
|
|
5194
|
+
);
|
|
5095
5195
|
}
|
|
5096
5196
|
} catch {
|
|
5097
|
-
showMicError(
|
|
5197
|
+
showMicError(
|
|
5198
|
+
"Could not access microphone. Please check your browser settings and allow microphone access for this site."
|
|
5199
|
+
);
|
|
5098
5200
|
}
|
|
5099
5201
|
} else {
|
|
5100
5202
|
showMicError("Could not access microphone: " + msg);
|
|
@@ -5149,7 +5251,10 @@ ${template}`;
|
|
|
5149
5251
|
SlashCommandMenu,
|
|
5150
5252
|
{
|
|
5151
5253
|
commands: filteredSlashCommands,
|
|
5152
|
-
selectedIndex: Math.min(
|
|
5254
|
+
selectedIndex: Math.min(
|
|
5255
|
+
selectedCommandIndex,
|
|
5256
|
+
filteredSlashCommands.length - 1
|
|
5257
|
+
),
|
|
5153
5258
|
onSelect: selectSlashCommand
|
|
5154
5259
|
}
|
|
5155
5260
|
),
|
|
@@ -5165,7 +5270,12 @@ ${template}`;
|
|
|
5165
5270
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
5166
5271
|
/* @__PURE__ */ jsx(ThinkingLevelSelector, {}),
|
|
5167
5272
|
/* @__PURE__ */ jsx(PersonaPicker, { onSelect: handlePersonaSelect }),
|
|
5168
|
-
/* @__PURE__ */ jsx(
|
|
5273
|
+
/* @__PURE__ */ jsx(
|
|
5274
|
+
CommandHelp,
|
|
5275
|
+
{
|
|
5276
|
+
onCommandSelect: (cmd) => handleValueChange(cmd + " ")
|
|
5277
|
+
}
|
|
5278
|
+
)
|
|
5169
5279
|
] }),
|
|
5170
5280
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
5171
5281
|
/* @__PURE__ */ jsx(
|
|
@@ -5175,26 +5285,32 @@ ${template}`;
|
|
|
5175
5285
|
disabled
|
|
5176
5286
|
}
|
|
5177
5287
|
),
|
|
5178
|
-
/* @__PURE__ */ jsx(
|
|
5179
|
-
|
|
5288
|
+
/* @__PURE__ */ jsx(
|
|
5289
|
+
PromptInputAction,
|
|
5180
5290
|
{
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
":",
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5291
|
+
tooltip: isRecording ? "Stop recording" : "Voice input",
|
|
5292
|
+
children: /* @__PURE__ */ jsx(
|
|
5293
|
+
Button,
|
|
5294
|
+
{
|
|
5295
|
+
onClick: handleMicClick,
|
|
5296
|
+
disabled: disabled || sttLoading,
|
|
5297
|
+
size: "icon-sm",
|
|
5298
|
+
variant: isRecording ? "destructive" : "ghost",
|
|
5299
|
+
className: `rounded-full ${isRecording ? "animate-pulse" : ""}`,
|
|
5300
|
+
"aria-label": isRecording ? "Stop recording" : "Voice input",
|
|
5301
|
+
children: sttLoading ? /* @__PURE__ */ jsx("span", { className: "size-4 animate-spin rounded-full border-2 border-current border-t-transparent" }) : isRecording ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
|
|
5302
|
+
/* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-red-500" }),
|
|
5303
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs tabular-nums", children: [
|
|
5304
|
+
Math.floor(recordingTime / 60),
|
|
5305
|
+
":",
|
|
5306
|
+
String(recordingTime % 60).padStart(2, "0")
|
|
5307
|
+
] }),
|
|
5308
|
+
/* @__PURE__ */ jsx(HugeiconsIcon, { icon: StopIcon, size: 14, strokeWidth: 2 })
|
|
5309
|
+
] }) : /* @__PURE__ */ jsx(HugeiconsIcon, { icon: Mic02Icon, size: 18, strokeWidth: 2 })
|
|
5310
|
+
}
|
|
5311
|
+
)
|
|
5196
5312
|
}
|
|
5197
|
-
)
|
|
5313
|
+
),
|
|
5198
5314
|
/* @__PURE__ */ jsx(PromptInputAction, { tooltip: "Send message", children: /* @__PURE__ */ jsx(
|
|
5199
5315
|
Button,
|
|
5200
5316
|
{
|
|
@@ -6065,7 +6181,6 @@ function useSwipeGesture(options) {
|
|
|
6065
6181
|
};
|
|
6066
6182
|
}
|
|
6067
6183
|
const ENABLED_KEY = "opencami-browser-notifications-enabled";
|
|
6068
|
-
const ASKED_KEY = "opencami-browser-notifications-permission-asked";
|
|
6069
6184
|
const NOTIFICATION_DEBOUNCE_MS = 5e3;
|
|
6070
6185
|
function isSupported() {
|
|
6071
6186
|
return typeof window !== "undefined" && "Notification" in window;
|
|
@@ -6098,10 +6213,6 @@ function useNotifications() {
|
|
|
6098
6213
|
}
|
|
6099
6214
|
if (nextEnabled && isSupported() && Notification.permission === "default") {
|
|
6100
6215
|
await requestPermission();
|
|
6101
|
-
try {
|
|
6102
|
-
localStorage.setItem(ASKED_KEY, "true");
|
|
6103
|
-
} catch {
|
|
6104
|
-
}
|
|
6105
6216
|
}
|
|
6106
6217
|
}, [requestPermission]);
|
|
6107
6218
|
const maybeNotifyAssistantMessage = useCallback((payload) => {
|
|
@@ -6122,32 +6233,6 @@ function useNotifications() {
|
|
|
6122
6233
|
notification.close();
|
|
6123
6234
|
};
|
|
6124
6235
|
}, [enabled, navigate]);
|
|
6125
|
-
useEffect(() => {
|
|
6126
|
-
if (!isSupported()) return;
|
|
6127
|
-
const onFirstInteraction = () => {
|
|
6128
|
-
if (Notification.permission !== "default") return;
|
|
6129
|
-
let asked = false;
|
|
6130
|
-
try {
|
|
6131
|
-
asked = localStorage.getItem(ASKED_KEY) === "true";
|
|
6132
|
-
} catch {
|
|
6133
|
-
asked = false;
|
|
6134
|
-
}
|
|
6135
|
-
if (asked) return;
|
|
6136
|
-
void requestPermission().finally(() => {
|
|
6137
|
-
try {
|
|
6138
|
-
localStorage.setItem(ASKED_KEY, "true");
|
|
6139
|
-
} catch {
|
|
6140
|
-
}
|
|
6141
|
-
});
|
|
6142
|
-
};
|
|
6143
|
-
const options = { once: true, passive: true };
|
|
6144
|
-
window.addEventListener("pointerdown", onFirstInteraction, options);
|
|
6145
|
-
window.addEventListener("keydown", onFirstInteraction, { once: true });
|
|
6146
|
-
return () => {
|
|
6147
|
-
window.removeEventListener("pointerdown", onFirstInteraction);
|
|
6148
|
-
window.removeEventListener("keydown", onFirstInteraction);
|
|
6149
|
-
};
|
|
6150
|
-
}, [requestPermission]);
|
|
6151
6236
|
useEffect(() => {
|
|
6152
6237
|
const sync = () => setEnabledState(getNotificationsEnabled());
|
|
6153
6238
|
window.addEventListener("storage", sync);
|
|
@@ -6166,7 +6251,7 @@ const KeyboardShortcutsDialog = lazy(
|
|
|
6166
6251
|
}))
|
|
6167
6252
|
);
|
|
6168
6253
|
const SearchDialog = lazy(
|
|
6169
|
-
() => import("./search-dialog-
|
|
6254
|
+
() => import("./search-dialog-CmI7naPN.js").then((m) => ({
|
|
6170
6255
|
default: m.SearchDialog
|
|
6171
6256
|
}))
|
|
6172
6257
|
);
|