opencami 1.3.2 → 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.
- package/README.md +60 -0
- package/dist/client/assets/CSPContext-EgWK8bIJ.js +1 -0
- package/dist/client/assets/DirectionContext-DXtY05YF.js +1 -0
- package/dist/client/assets/_sessionKey-B89e7G3y.js +100 -0
- package/dist/client/assets/agents-screen-1BiEZ9od.js +1 -0
- package/dist/client/assets/agents-x54ocA9z.js +2 -0
- package/dist/client/assets/bots-screen-BNQciUeJ.js +1 -0
- package/dist/client/assets/bots-x86ZHG4b.js +2 -0
- package/dist/client/assets/button-nDcsaNPl.js +1 -0
- package/dist/client/assets/{connect-CtDn993i.js → connect-w4lLOqiJ.js} +1 -1
- package/dist/client/assets/file-explorer-screen-CAsjd3w8.js +1 -0
- package/dist/client/assets/files-Bype5Mnb.js +2 -0
- package/dist/client/assets/{index-N9-2R5hZ.js → index-36G0WCxU.js} +1 -1
- package/dist/client/assets/index-BXkRE220.js +153 -0
- package/dist/client/assets/keyboard-shortcuts-dialog-BdCeXRjD.js +1 -0
- package/dist/client/assets/{main-DrVY5UJU.js → main-B3N0eQFg.js} +129 -17
- package/dist/client/assets/opencami-logo-DD0DPFRQ.js +1 -0
- package/dist/client/assets/{react-CzqI3gbN.js → react-B16OrBeM.js} +1 -1
- package/dist/client/assets/search-dialog-BjTPceEl.js +1 -0
- package/dist/client/assets/session-export-dialog-DtHKG2zW.js +1 -0
- package/dist/client/assets/settings-dialog-hiqdk_UD.js +1 -0
- package/dist/client/assets/skills-DhwyFq3y.js +2 -0
- package/dist/client/assets/skills-panel-BLUjzfjJ.js +5 -0
- package/dist/client/assets/styles-CHP4l6vZ.css +1 -0
- package/dist/client/assets/switch-J6wLIVu2.js +1 -0
- package/dist/client/assets/tabs-DvPgTz5I.js +1 -0
- package/dist/client/assets/tooltip-C14vdXHK.js +1 -0
- package/dist/client/assets/use-file-explorer-state-BnaJEqRP.js +12 -0
- package/dist/client/assets/useButton-Bnnac1eR.js +1 -0
- package/dist/client/assets/useCompositeItem-BgiEMKAt.js +1 -0
- package/dist/client/assets/useControlled-BhUuiHAm.js +1 -0
- package/dist/client/assets/useMutation-CFmVaBag.js +1 -0
- package/dist/client/assets/visuallyHidden-DCCICp6T.js +9 -0
- package/dist/server/assets/{_sessionKey-DVNrEYFh.js → _sessionKey-tRze5NLR.js} +493 -92
- package/dist/server/assets/_tanstack-start-manifest_v-CyfoMvUa.js +4 -0
- package/dist/server/assets/{agents-Dz_i76VW.js → agents-CmQ4vvXm.js} +1 -1
- package/dist/server/assets/{agents-screen-CqQPJndp.js → agents-screen-bmrIyFbk.js} +43 -35
- package/dist/server/assets/bots-Byt6jv0a.js +11 -0
- package/dist/server/assets/bots-screen-C2TGFv42.js +474 -0
- package/dist/server/assets/{button-DtQ3rV1m.js → button-CwY2OHFj.js} +2 -2
- package/dist/server/assets/{connect-CIDOw12K.js → connect-d3AqjAqe.js} +2 -2
- package/dist/server/assets/{file-explorer-screen-Cx0jiLRU.js → file-explorer-screen-CVlFiAFu.js} +39 -40
- package/dist/server/assets/{files-Trs1M5ba.js → files-BIEcSPGp.js} +1 -1
- package/dist/server/assets/{index-CmbNTqa2.js → index-CNIATlJ9.js} +93 -38
- package/dist/server/assets/{index-Dv2RXDa2.js → index-CRfLKh30.js} +2 -1
- package/dist/server/assets/{keyboard-shortcuts-dialog-7OEtXUlW.js → keyboard-shortcuts-dialog-CsNP85q8.js} +2 -2
- package/dist/server/assets/{router-OoQe2c20.js → router-rn7pJO_D.js} +515 -78
- package/dist/server/assets/{search-dialog-Bq0Pnxdb.js → search-dialog-Bz4Cu0KW.js} +23 -6
- package/dist/server/assets/{session-export-dialog-DRVbC8Q-.js → session-export-dialog-CwclV0Aj.js} +2 -2
- package/dist/server/assets/{settings-dialog-BsJsnMiu.js → settings-dialog-BBM7jCjE.js} +409 -95
- package/dist/server/assets/skills-Cy8xclXY.js +11 -0
- package/dist/server/assets/skills-panel-BnRNb7u9.js +762 -0
- package/dist/server/assets/{switch-DnX0MjGS.js → switch-BbkUeVDV.js} +1 -1
- package/dist/server/assets/tabs-DDFZob0m.js +67 -0
- package/dist/server/assets/{tooltip-gbV6rEVv.js → tooltip-DgsSPocE.js} +1 -1
- package/dist/server/assets/{use-file-explorer-state-DMHdtb7D.js → use-file-explorer-state-Il1LlBAe.js} +13 -1
- package/dist/server/server.js +2 -2
- package/package.json +6 -2
- package/dist/client/assets/_sessionKey-Z6Wcnj0N.js +0 -97
- package/dist/client/assets/agents-D8ZHVQ1Z.js +0 -2
- package/dist/client/assets/agents-screen-BVK0QTRH.js +0 -1
- package/dist/client/assets/button-CuH8u1uR.js +0 -1
- package/dist/client/assets/file-explorer-screen-DMUuR1uG.js +0 -1
- package/dist/client/assets/files-CDMLoJ0u.js +0 -2
- package/dist/client/assets/index-IGP-Igwt.js +0 -153
- package/dist/client/assets/keyboard-shortcuts-dialog-DW--4YLF.js +0 -1
- package/dist/client/assets/opencami-logo-ChD2XR2j.js +0 -1
- package/dist/client/assets/search-dialog-DYyFYJmw.js +0 -1
- package/dist/client/assets/session-export-dialog-BFizBmGb.js +0 -1
- package/dist/client/assets/settings-dialog-UvgVi2It.js +0 -1
- package/dist/client/assets/styles-BGTCU8mq.css +0 -1
- package/dist/client/assets/switch-DxW2OWPG.js +0 -1
- package/dist/client/assets/use-file-explorer-state-Cii59H70.js +0 -12
- package/dist/client/assets/useButton-hZdvKtl_.js +0 -9
- package/dist/server/assets/_tanstack-start-manifest_v-PwRq_yJS.js +0 -4
|
@@ -3,12 +3,12 @@ import { Link, useNavigate } from "@tanstack/react-router";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import React__default, { memo, useDeferredValue, useState, useMemo, useCallback, Suspense, lazy, useRef, useEffect, useId, useLayoutEffect, createContext, useContext } from "react";
|
|
5
5
|
import { useQueryClient, useMutation, useQuery } from "@tanstack/react-query";
|
|
6
|
-
import { T as TooltipProvider, a as TooltipRoot, b as TooltipTrigger, c as TooltipContent, s as setChatUiState, d as chatUiQueryKey, g as getChatUiState } from "./tooltip-
|
|
6
|
+
import { T as TooltipProvider, a as TooltipRoot, b as TooltipTrigger, c as TooltipContent, s as setChatUiState, d as chatUiQueryKey, g as getChatUiState } from "./tooltip-DgsSPocE.js";
|
|
7
7
|
import { HugeiconsIcon } from "@hugeicons/react";
|
|
8
|
-
import { Tick01Icon, Cancel01Icon, MoreHorizontalIcon, Pen01Icon, Upload01Icon, Delete01Icon, BotIcon, Clock01Icon, Chat01Icon, ArrowRight01Icon, SidebarLeft01Icon, PencilEdit02Icon, Folder01Icon, AiBrain01Icon, Search01Icon, Settings01Icon, Menu01Icon, Tick02Icon, Copy01Icon, Loading02Icon, StopIcon, VolumeHighIcon, ArrowDown01Icon, Loading03Icon, ArtificialIntelligence02Icon, CommandIcon, Attachment01Icon, File01Icon, Mic02Icon, ArrowUp02Icon } from "@hugeicons/core-free-icons";
|
|
8
|
+
import { Tick01Icon, Cancel01Icon, MoreHorizontalIcon, Pen01Icon, Upload01Icon, Delete01Icon, BotIcon, Clock01Icon, Chat01Icon, ArrowRight01Icon, SidebarLeft01Icon, PencilEdit02Icon, Folder01Icon, PackageOpenIcon, AiBrain01Icon, SmartPhone01Icon, Search01Icon, Settings01Icon, Menu01Icon, Tick02Icon, Copy01Icon, Loading02Icon, StopIcon, VolumeHighIcon, ArrowDown01Icon, Loading03Icon, ArtificialIntelligence02Icon, CommandIcon, Attachment01Icon, File01Icon, Mic02Icon, ArrowUp02Icon } from "@hugeicons/core-free-icons";
|
|
9
9
|
import { motion, AnimatePresence } from "motion/react";
|
|
10
|
-
import { D as DialogRoot, a as DialogContent, b as DialogTitle, c as DialogDescription, d as DialogClose, M as MenuRoot, e as MenuTrigger, f as MenuContent, g as MenuItem, u as useFileExplorerState } from "./use-file-explorer-state-
|
|
11
|
-
import { B as Button, c as cn, b as buttonVariants } from "./button-
|
|
10
|
+
import { D as DialogRoot, a as DialogContent, b as DialogTitle, c as DialogDescription, d as DialogClose, M as MenuRoot, e as MenuTrigger, f as MenuContent, g as MenuItem, u as useFileExplorerState } from "./use-file-explorer-state-Il1LlBAe.js";
|
|
11
|
+
import { B as Button, c as cn, b as buttonVariants } from "./button-CwY2OHFj.js";
|
|
12
12
|
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
13
13
|
import { Collapsible as Collapsible$1 } from "@base-ui/react/collapsible";
|
|
14
14
|
import { ScrollArea } from "@base-ui/react/scroll-area";
|
|
@@ -17,11 +17,11 @@ import { marked } from "marked";
|
|
|
17
17
|
import ReactMarkdown from "react-markdown";
|
|
18
18
|
import remarkBreaks from "remark-breaks";
|
|
19
19
|
import remarkGfm from "remark-gfm";
|
|
20
|
-
import { r as resolveLanguage,
|
|
20
|
+
import { r as resolveLanguage, C as CodeBlock, u as useChatSettings$1 } from "./index-CNIATlJ9.js";
|
|
21
21
|
import { create } from "zustand";
|
|
22
22
|
import { persist } from "zustand/middleware";
|
|
23
23
|
import { createPortal } from "react-dom";
|
|
24
|
-
import { a as Route } from "./router-
|
|
24
|
+
import { a as Route } from "./router-rn7pJO_D.js";
|
|
25
25
|
function deriveFriendlyIdFromKey(key) {
|
|
26
26
|
if (!key) return "main";
|
|
27
27
|
const trimmed = key.trim();
|
|
@@ -758,7 +758,7 @@ function SessionItemComponent({
|
|
|
758
758
|
"group inline-flex items-center justify-between",
|
|
759
759
|
"w-full text-left pl-1.5 pr-0.5 min-h-8 py-1 rounded-lg transition-colors duration-0",
|
|
760
760
|
"select-none",
|
|
761
|
-
active ? "bg-
|
|
761
|
+
active ? "bg-[var(--opencami-accent-light)] text-[var(--opencami-accent)]" : "bg-transparent text-primary-950 [&:hover:not(:has(button:hover))]:bg-primary-200"
|
|
762
762
|
),
|
|
763
763
|
children: [
|
|
764
764
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [
|
|
@@ -784,7 +784,7 @@ function SessionItemComponent({
|
|
|
784
784
|
className: "text-primary-500/70 shrink-0"
|
|
785
785
|
}
|
|
786
786
|
),
|
|
787
|
-
/* @__PURE__ */ jsxs("div", { className: "text-sm font-[450]
|
|
787
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 truncate text-sm font-[450]", title: label, children: [
|
|
788
788
|
isPinned ? /* @__PURE__ */ jsx("span", { className: "mr-1 text-xs text-primary-700", "aria-hidden": "true", children: "📌" }) : null,
|
|
789
789
|
label
|
|
790
790
|
] }),
|
|
@@ -1114,13 +1114,28 @@ const SidebarSessions = memo(function SidebarSessions2({
|
|
|
1114
1114
|
`Delete ${selectedSessions.length} sessions? This will archive them.`
|
|
1115
1115
|
);
|
|
1116
1116
|
if (!confirmed) return;
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1117
|
+
const failedSessionLabels = [];
|
|
1118
|
+
await runWithConcurrency(
|
|
1119
|
+
selectedSessions,
|
|
1119
1120
|
10,
|
|
1120
|
-
|
|
1121
|
+
async (session) => {
|
|
1122
|
+
try {
|
|
1123
|
+
await deleteSessionRequest(session.key);
|
|
1124
|
+
} catch (err) {
|
|
1125
|
+
failedSessionLabels.push(
|
|
1126
|
+
session.label || session.title || session.derivedTitle || session.friendlyId
|
|
1127
|
+
);
|
|
1128
|
+
throw err;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1121
1131
|
);
|
|
1122
|
-
if (
|
|
1123
|
-
console.error("[sidebar] Bulk delete failed for some sessions",
|
|
1132
|
+
if (failedSessionLabels.length > 0) {
|
|
1133
|
+
console.error("[sidebar] Bulk delete failed for some sessions", failedSessionLabels);
|
|
1134
|
+
window.alert(
|
|
1135
|
+
`Could not delete ${failedSessionLabels.length} session${failedSessionLabels.length !== 1 ? "s" : ""}:
|
|
1136
|
+
|
|
1137
|
+
${failedSessionLabels.join("\n")}`
|
|
1138
|
+
);
|
|
1124
1139
|
}
|
|
1125
1140
|
setSelectionMode(false);
|
|
1126
1141
|
setSelectedSessionKeys(/* @__PURE__ */ new Set());
|
|
@@ -1649,10 +1664,10 @@ function useRenameSession() {
|
|
|
1649
1664
|
return { renameSession, renaming, error };
|
|
1650
1665
|
}
|
|
1651
1666
|
const SettingsDialog = lazy(
|
|
1652
|
-
() => import("./settings-dialog-
|
|
1667
|
+
() => import("./settings-dialog-BBM7jCjE.js").then((m) => ({ default: m.SettingsDialog }))
|
|
1653
1668
|
);
|
|
1654
1669
|
const SessionExportDialog = lazy(
|
|
1655
|
-
() => import("./session-export-dialog-
|
|
1670
|
+
() => import("./session-export-dialog-CwclV0Aj.js").then((m) => ({
|
|
1656
1671
|
default: m.SessionExportDialog
|
|
1657
1672
|
}))
|
|
1658
1673
|
);
|
|
@@ -1762,7 +1777,7 @@ function ChatSidebarComponent({
|
|
|
1762
1777
|
motion.aside,
|
|
1763
1778
|
{
|
|
1764
1779
|
initial: false,
|
|
1765
|
-
animate: { width: isCollapsed ? 48 :
|
|
1780
|
+
animate: { width: isCollapsed ? 48 : "var(--opencami-sidebar-width)" },
|
|
1766
1781
|
transition,
|
|
1767
1782
|
className: asideProps.className,
|
|
1768
1783
|
children: [
|
|
@@ -1893,6 +1908,48 @@ function ChatSidebarComponent({
|
|
|
1893
1908
|
) }),
|
|
1894
1909
|
isCollapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Files" })
|
|
1895
1910
|
] }) }),
|
|
1911
|
+
(() => {
|
|
1912
|
+
try {
|
|
1913
|
+
return localStorage.getItem("opencami-skills-browser") === "true";
|
|
1914
|
+
} catch {
|
|
1915
|
+
return false;
|
|
1916
|
+
}
|
|
1917
|
+
})() && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { children: [
|
|
1918
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1919
|
+
Link,
|
|
1920
|
+
{
|
|
1921
|
+
to: "/skills",
|
|
1922
|
+
className: cn(
|
|
1923
|
+
buttonVariants({ variant: "ghost", size: "sm" }),
|
|
1924
|
+
"w-full pl-1.5 justify-start"
|
|
1925
|
+
),
|
|
1926
|
+
onClick: onSelectSession,
|
|
1927
|
+
children: [
|
|
1928
|
+
/* @__PURE__ */ jsx(
|
|
1929
|
+
HugeiconsIcon,
|
|
1930
|
+
{
|
|
1931
|
+
icon: PackageOpenIcon,
|
|
1932
|
+
size: 20,
|
|
1933
|
+
strokeWidth: 1.5,
|
|
1934
|
+
className: "min-w-5"
|
|
1935
|
+
}
|
|
1936
|
+
),
|
|
1937
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: !isCollapsed && /* @__PURE__ */ jsx(
|
|
1938
|
+
motion.span,
|
|
1939
|
+
{
|
|
1940
|
+
initial: { opacity: 0 },
|
|
1941
|
+
animate: { opacity: 1 },
|
|
1942
|
+
exit: { opacity: 0 },
|
|
1943
|
+
transition,
|
|
1944
|
+
className: "overflow-hidden whitespace-nowrap",
|
|
1945
|
+
children: "Skills"
|
|
1946
|
+
}
|
|
1947
|
+
) })
|
|
1948
|
+
]
|
|
1949
|
+
}
|
|
1950
|
+
) }),
|
|
1951
|
+
isCollapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Skills" })
|
|
1952
|
+
] }) }),
|
|
1896
1953
|
(() => {
|
|
1897
1954
|
try {
|
|
1898
1955
|
return localStorage.getItem("opencami-agent-manager") === "true";
|
|
@@ -1934,6 +1991,48 @@ function ChatSidebarComponent({
|
|
|
1934
1991
|
}
|
|
1935
1992
|
) }),
|
|
1936
1993
|
isCollapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Agents" })
|
|
1994
|
+
] }) }),
|
|
1995
|
+
(() => {
|
|
1996
|
+
try {
|
|
1997
|
+
return localStorage.getItem("opencami-cron-manager") === "true";
|
|
1998
|
+
} catch {
|
|
1999
|
+
return false;
|
|
2000
|
+
}
|
|
2001
|
+
})() && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { children: [
|
|
2002
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
2003
|
+
Link,
|
|
2004
|
+
{
|
|
2005
|
+
to: "/bots",
|
|
2006
|
+
className: cn(
|
|
2007
|
+
buttonVariants({ variant: "ghost", size: "sm" }),
|
|
2008
|
+
"w-full pl-1.5 justify-start"
|
|
2009
|
+
),
|
|
2010
|
+
onClick: onSelectSession,
|
|
2011
|
+
children: [
|
|
2012
|
+
/* @__PURE__ */ jsx(
|
|
2013
|
+
HugeiconsIcon,
|
|
2014
|
+
{
|
|
2015
|
+
icon: SmartPhone01Icon,
|
|
2016
|
+
size: 20,
|
|
2017
|
+
strokeWidth: 1.5,
|
|
2018
|
+
className: "min-w-5"
|
|
2019
|
+
}
|
|
2020
|
+
),
|
|
2021
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: !isCollapsed && /* @__PURE__ */ jsx(
|
|
2022
|
+
motion.span,
|
|
2023
|
+
{
|
|
2024
|
+
initial: { opacity: 0 },
|
|
2025
|
+
animate: { opacity: 1 },
|
|
2026
|
+
exit: { opacity: 0 },
|
|
2027
|
+
transition,
|
|
2028
|
+
className: "overflow-hidden whitespace-nowrap",
|
|
2029
|
+
children: "Cron Jobs"
|
|
2030
|
+
}
|
|
2031
|
+
) })
|
|
2032
|
+
]
|
|
2033
|
+
}
|
|
2034
|
+
) }),
|
|
2035
|
+
isCollapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Cron Jobs" })
|
|
1937
2036
|
] }) })
|
|
1938
2037
|
]
|
|
1939
2038
|
}
|
|
@@ -2281,7 +2380,8 @@ function ChatHeaderComponent({
|
|
|
2281
2380
|
"div",
|
|
2282
2381
|
{
|
|
2283
2382
|
ref: wrapperRef,
|
|
2284
|
-
|
|
2383
|
+
"data-tauri-drag-region": true,
|
|
2384
|
+
className: "border-b border-primary-200 px-4 h-12 flex min-w-0 items-center overflow-x-hidden bg-surface tauri-drag-header",
|
|
2285
2385
|
children: [
|
|
2286
2386
|
showSidebarButton ? /* @__PURE__ */ jsx(
|
|
2287
2387
|
Button,
|
|
@@ -2290,11 +2390,12 @@ function ChatHeaderComponent({
|
|
|
2290
2390
|
variant: "ghost",
|
|
2291
2391
|
onClick: onOpenSidebar,
|
|
2292
2392
|
className: "mr-2 text-primary-800 hover:bg-primary-100",
|
|
2393
|
+
style: { WebkitAppRegion: "no-drag" },
|
|
2293
2394
|
"aria-label": "Open sidebar",
|
|
2294
2395
|
children: /* @__PURE__ */ jsx(HugeiconsIcon, { icon: Menu01Icon, size: 18, strokeWidth: 1.6 })
|
|
2295
2396
|
}
|
|
2296
2397
|
) : null,
|
|
2297
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
2398
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0 overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium", children: activeTitle }) }),
|
|
2298
2399
|
/* @__PURE__ */ jsx(
|
|
2299
2400
|
MemoizedContextMeter,
|
|
2300
2401
|
{
|
|
@@ -2523,6 +2624,108 @@ function MessageActionsBar({
|
|
|
2523
2624
|
}
|
|
2524
2625
|
);
|
|
2525
2626
|
}
|
|
2627
|
+
const KNOWN_FILE_EXTENSIONS = [
|
|
2628
|
+
"md",
|
|
2629
|
+
"txt",
|
|
2630
|
+
"json",
|
|
2631
|
+
"yaml",
|
|
2632
|
+
"yml",
|
|
2633
|
+
"toml",
|
|
2634
|
+
"py",
|
|
2635
|
+
"js",
|
|
2636
|
+
"ts",
|
|
2637
|
+
"tsx",
|
|
2638
|
+
"jsx",
|
|
2639
|
+
"css",
|
|
2640
|
+
"scss",
|
|
2641
|
+
"html",
|
|
2642
|
+
"xml",
|
|
2643
|
+
"sh",
|
|
2644
|
+
"bash",
|
|
2645
|
+
"go",
|
|
2646
|
+
"rs",
|
|
2647
|
+
"rb",
|
|
2648
|
+
"php",
|
|
2649
|
+
"java",
|
|
2650
|
+
"kt",
|
|
2651
|
+
"swift",
|
|
2652
|
+
"c",
|
|
2653
|
+
"cpp",
|
|
2654
|
+
"h",
|
|
2655
|
+
"hpp",
|
|
2656
|
+
"sql",
|
|
2657
|
+
"graphql",
|
|
2658
|
+
"dockerfile",
|
|
2659
|
+
"env",
|
|
2660
|
+
"conf",
|
|
2661
|
+
"cfg",
|
|
2662
|
+
"ini",
|
|
2663
|
+
"log",
|
|
2664
|
+
"csv"
|
|
2665
|
+
];
|
|
2666
|
+
const EXTENSION_PATTERN = KNOWN_FILE_EXTENSIONS.join("|");
|
|
2667
|
+
const ABSOLUTE_OR_HOME_PATH_PATTERN = "(?:~\\/[A-Za-z0-9._\\-\\/]*[A-Za-z0-9._\\-\\/]|\\/(?:[\\w.\\-]+\\/)*[\\w.\\-]+\\/?)";
|
|
2668
|
+
const RELATIVE_PATH_PATTERN = "(?:[A-Za-z0-9._\\-]+(?:\\/[A-Za-z0-9._\\-]+)+\\/?)";
|
|
2669
|
+
const BARE_FILENAME_PATTERN = `(?:[A-Za-z0-9_-][A-Za-z0-9._-]*[A-Za-z0-9_-]\\.(?:${EXTENSION_PATTERN})|dockerfile)`;
|
|
2670
|
+
const FILE_PATH_REGEX = new RegExp(
|
|
2671
|
+
`(^|[\\s"'(,;:])(${ABSOLUTE_OR_HOME_PATH_PATTERN}|${RELATIVE_PATH_PATTERN}|${BARE_FILENAME_PATTERN})(?=$|[\\s"'),;:!?])`,
|
|
2672
|
+
"gi"
|
|
2673
|
+
);
|
|
2674
|
+
function trimTrailingPunctuation(path) {
|
|
2675
|
+
if (!path) return { path: path ?? "", trailing: "" };
|
|
2676
|
+
const match = path.match(/^(.*?)([),.;:!?]+)?$/);
|
|
2677
|
+
if (!match) return { path, trailing: "" };
|
|
2678
|
+
return { path: match[1] || path, trailing: match[2] || "" };
|
|
2679
|
+
}
|
|
2680
|
+
function isLikelyFilePath(text) {
|
|
2681
|
+
if (!text) return false;
|
|
2682
|
+
FILE_PATH_REGEX.lastIndex = 0;
|
|
2683
|
+
const match = FILE_PATH_REGEX.exec(text);
|
|
2684
|
+
if (!match) return false;
|
|
2685
|
+
const prefix = match[1] || "";
|
|
2686
|
+
const value = match[2] || "";
|
|
2687
|
+
const matchStart = match.index + prefix.length;
|
|
2688
|
+
const matchEnd = matchStart + value.length;
|
|
2689
|
+
return matchStart === 0 && matchEnd === text.length;
|
|
2690
|
+
}
|
|
2691
|
+
function splitTextByFilePaths(text) {
|
|
2692
|
+
if (!text) return [{ type: "text", value: text }];
|
|
2693
|
+
const segments = [];
|
|
2694
|
+
let lastIndex = 0;
|
|
2695
|
+
FILE_PATH_REGEX.lastIndex = 0;
|
|
2696
|
+
let match;
|
|
2697
|
+
while ((match = FILE_PATH_REGEX.exec(text)) !== null) {
|
|
2698
|
+
const prefix = match[1] || "";
|
|
2699
|
+
const rawPath = match[2] || "";
|
|
2700
|
+
const fullMatch = match[0];
|
|
2701
|
+
const start = match.index;
|
|
2702
|
+
const prefixStart = start;
|
|
2703
|
+
const pathStart = start + prefix.length;
|
|
2704
|
+
if (prefixStart > lastIndex) {
|
|
2705
|
+
segments.push({ type: "text", value: text.slice(lastIndex, prefixStart) });
|
|
2706
|
+
}
|
|
2707
|
+
if (prefix) {
|
|
2708
|
+
segments.push({ type: "text", value: prefix });
|
|
2709
|
+
}
|
|
2710
|
+
const { path, trailing } = trimTrailingPunctuation(rawPath);
|
|
2711
|
+
if (path.length > 1) {
|
|
2712
|
+
segments.push({ type: "path", value: path });
|
|
2713
|
+
if (trailing) {
|
|
2714
|
+
segments.push({ type: "text", value: trailing });
|
|
2715
|
+
}
|
|
2716
|
+
} else {
|
|
2717
|
+
segments.push({ type: "text", value: fullMatch });
|
|
2718
|
+
}
|
|
2719
|
+
lastIndex = pathStart + rawPath.length;
|
|
2720
|
+
}
|
|
2721
|
+
if (lastIndex < text.length) {
|
|
2722
|
+
segments.push({ type: "text", value: text.slice(lastIndex) });
|
|
2723
|
+
}
|
|
2724
|
+
return segments.length > 0 ? segments : [{ type: "text", value: text }];
|
|
2725
|
+
}
|
|
2726
|
+
function filePathToMarkdownHref(path) {
|
|
2727
|
+
return `openclaw-file://${encodeURIComponent(path)}`;
|
|
2728
|
+
}
|
|
2526
2729
|
function markdownHrefToFilePath(href) {
|
|
2527
2730
|
if (!href?.startsWith("openclaw-file://")) return null;
|
|
2528
2731
|
try {
|
|
@@ -2531,6 +2734,39 @@ function markdownHrefToFilePath(href) {
|
|
|
2531
2734
|
return null;
|
|
2532
2735
|
}
|
|
2533
2736
|
}
|
|
2737
|
+
function remarkFilePathLinks() {
|
|
2738
|
+
return (tree) => {
|
|
2739
|
+
function visit(node, parent) {
|
|
2740
|
+
if (!node) return;
|
|
2741
|
+
if (node.type === "text" && parent && parent.type !== "link" && parent.type !== "inlineCode" && parent.type !== "code") {
|
|
2742
|
+
const segments = splitTextByFilePaths(String(node.value || ""));
|
|
2743
|
+
const hasPaths = segments.some((segment) => segment.type === "path");
|
|
2744
|
+
if (!hasPaths) return;
|
|
2745
|
+
const replacement = segments.map((segment) => {
|
|
2746
|
+
if (segment.type === "text") {
|
|
2747
|
+
return { type: "text", value: segment.value };
|
|
2748
|
+
}
|
|
2749
|
+
return {
|
|
2750
|
+
type: "link",
|
|
2751
|
+
url: filePathToMarkdownHref(segment.value),
|
|
2752
|
+
children: [{ type: "text", value: segment.value }]
|
|
2753
|
+
};
|
|
2754
|
+
});
|
|
2755
|
+
const index = parent.children.indexOf(node);
|
|
2756
|
+
if (index >= 0) {
|
|
2757
|
+
parent.children.splice(index, 1, ...replacement);
|
|
2758
|
+
}
|
|
2759
|
+
return;
|
|
2760
|
+
}
|
|
2761
|
+
if (Array.isArray(node.children)) {
|
|
2762
|
+
for (const child of [...node.children]) {
|
|
2763
|
+
visit(child, node);
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
visit(tree, null);
|
|
2768
|
+
};
|
|
2769
|
+
}
|
|
2534
2770
|
const EXTENSION_LANGUAGE_MAP = {
|
|
2535
2771
|
py: "python",
|
|
2536
2772
|
ts: "typescript",
|
|
@@ -2574,27 +2810,67 @@ function languageFromFilePath(path) {
|
|
|
2574
2810
|
return resolveLanguage(mapped);
|
|
2575
2811
|
}
|
|
2576
2812
|
const INLINE_PREVIEW_MAX_BYTES = 100 * 1024;
|
|
2813
|
+
function normalizeClickedPath(path) {
|
|
2814
|
+
if (!path) return "/";
|
|
2815
|
+
return path.includes("/") ? path : `/${path}`;
|
|
2816
|
+
}
|
|
2817
|
+
function toWorkspacePath(path) {
|
|
2818
|
+
let p = normalizeClickedPath(path);
|
|
2819
|
+
const prefixes = ["/root/clawd/", "/root/"];
|
|
2820
|
+
for (const prefix of prefixes) {
|
|
2821
|
+
if (p.startsWith(prefix)) {
|
|
2822
|
+
p = "/" + p.slice(prefix.length);
|
|
2823
|
+
break;
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
return p.startsWith("/") ? p : `/${p}`;
|
|
2827
|
+
}
|
|
2828
|
+
function hasExtension(path) {
|
|
2829
|
+
const trimmed = path.replace(/\/+$/, "");
|
|
2830
|
+
const name = trimmed.split("/").pop() || "";
|
|
2831
|
+
if (!name || name.startsWith(".")) return false;
|
|
2832
|
+
return name.includes(".");
|
|
2833
|
+
}
|
|
2834
|
+
function isDirectoryPathHeuristic(path) {
|
|
2835
|
+
if (!path) return false;
|
|
2836
|
+
return path.endsWith("/") || !hasExtension(path);
|
|
2837
|
+
}
|
|
2838
|
+
function isDirectoryError(code, message) {
|
|
2839
|
+
const normalizedCode = String(code || "").toUpperCase();
|
|
2840
|
+
const normalizedMessage = String(message || "").toLowerCase();
|
|
2841
|
+
return normalizedCode.includes("DIRECTORY") || normalizedMessage.includes("is a directory") || normalizedMessage.includes("directory");
|
|
2842
|
+
}
|
|
2577
2843
|
function parseMarkdownIntoBlocks(markdown) {
|
|
2578
2844
|
const tokens = marked.lexer(markdown);
|
|
2579
2845
|
return tokens.map((token) => token.raw);
|
|
2580
2846
|
}
|
|
2581
2847
|
function extractLanguage(className) {
|
|
2582
2848
|
if (!className) return "text";
|
|
2583
|
-
const match = className.match(/language-(\w+)/);
|
|
2849
|
+
const match = className.match(/language-([\w-]+)/);
|
|
2584
2850
|
return match ? match[1] : "text";
|
|
2585
2851
|
}
|
|
2852
|
+
function extractFilenameFromMeta(meta) {
|
|
2853
|
+
const value = meta?.trim();
|
|
2854
|
+
if (!value) return void 0;
|
|
2855
|
+
const firstToken = value.split(/\s+/)[0];
|
|
2856
|
+
return firstToken || void 0;
|
|
2857
|
+
}
|
|
2586
2858
|
const BASE_COMPONENTS = {
|
|
2587
|
-
code: function CodeComponent({ className, children }) {
|
|
2859
|
+
code: function CodeComponent({ className, children, node }) {
|
|
2588
2860
|
const isInline = !className?.includes("language-");
|
|
2589
2861
|
if (isInline) {
|
|
2590
2862
|
return /* @__PURE__ */ jsx("code", { className: "rounded bg-primary-100 px-1.5 py-1 text-sm font-mono text-primary-900 border border-primary-200", children });
|
|
2591
2863
|
}
|
|
2592
2864
|
const language = extractLanguage(className);
|
|
2865
|
+
const filename = extractFilenameFromMeta(
|
|
2866
|
+
node?.data?.meta
|
|
2867
|
+
);
|
|
2593
2868
|
return /* @__PURE__ */ jsx(
|
|
2594
2869
|
CodeBlock,
|
|
2595
2870
|
{
|
|
2596
2871
|
content: String(children ?? ""),
|
|
2597
2872
|
language,
|
|
2873
|
+
filename,
|
|
2598
2874
|
className: "w-full"
|
|
2599
2875
|
}
|
|
2600
2876
|
);
|
|
@@ -2654,19 +2930,18 @@ const BASE_COMPONENTS = {
|
|
|
2654
2930
|
return /* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-primary-950", children });
|
|
2655
2931
|
}
|
|
2656
2932
|
};
|
|
2657
|
-
function createDefaultComponents(onOpenFilePreview
|
|
2658
|
-
const FILE_PATH_RE = /^(?:~\/[\w.\-\/]+|\/(?:[\w.\-]+\/)+[\w.\-]+)$/;
|
|
2933
|
+
function createDefaultComponents(onOpenFilePreview) {
|
|
2659
2934
|
return {
|
|
2660
2935
|
...BASE_COMPONENTS,
|
|
2661
2936
|
a: function AComponent({ children, href }) {
|
|
2662
2937
|
const filePath = markdownHrefToFilePath(href);
|
|
2663
|
-
if (
|
|
2938
|
+
if (filePath) {
|
|
2664
2939
|
return /* @__PURE__ */ jsx(
|
|
2665
2940
|
"button",
|
|
2666
2941
|
{
|
|
2667
2942
|
type: "button",
|
|
2668
2943
|
onClick: () => onOpenFilePreview(filePath),
|
|
2669
|
-
className: "font-mono text-
|
|
2944
|
+
className: "font-mono text-[var(--opencami-accent)] underline decoration-[var(--opencami-accent-light)] underline-offset-4 hover:opacity-90 cursor-pointer",
|
|
2670
2945
|
children
|
|
2671
2946
|
}
|
|
2672
2947
|
);
|
|
@@ -2675,17 +2950,34 @@ function createDefaultComponents(onOpenFilePreview, inlineFilePreviewEnabled) {
|
|
|
2675
2950
|
"a",
|
|
2676
2951
|
{
|
|
2677
2952
|
href,
|
|
2678
|
-
|
|
2953
|
+
onClick: (event) => {
|
|
2954
|
+
if (href?.startsWith("openclaw-file://")) event.preventDefault();
|
|
2955
|
+
},
|
|
2956
|
+
className: "text-[var(--opencami-accent)] underline decoration-[var(--opencami-accent-light)] underline-offset-4 transition-opacity hover:opacity-90",
|
|
2679
2957
|
target: "_blank",
|
|
2680
2958
|
rel: "noopener noreferrer",
|
|
2681
2959
|
children
|
|
2682
2960
|
}
|
|
2683
2961
|
);
|
|
2684
2962
|
},
|
|
2685
|
-
code: function InlineCodeComponent({ children, className }) {
|
|
2686
|
-
if (className
|
|
2963
|
+
code: function InlineCodeComponent({ children, className, node }) {
|
|
2964
|
+
if (className?.includes("language-")) {
|
|
2965
|
+
const language = extractLanguage(className);
|
|
2966
|
+
const filename = extractFilenameFromMeta(
|
|
2967
|
+
node?.data?.meta
|
|
2968
|
+
);
|
|
2969
|
+
return /* @__PURE__ */ jsx(
|
|
2970
|
+
CodeBlock,
|
|
2971
|
+
{
|
|
2972
|
+
content: String(children ?? ""),
|
|
2973
|
+
language,
|
|
2974
|
+
filename,
|
|
2975
|
+
className: "w-full"
|
|
2976
|
+
}
|
|
2977
|
+
);
|
|
2978
|
+
}
|
|
2687
2979
|
const text = typeof children === "string" ? children : Array.isArray(children) ? children.filter((c) => typeof c === "string").join("") : String(children ?? "");
|
|
2688
|
-
if (
|
|
2980
|
+
if (text && isLikelyFilePath(text)) {
|
|
2689
2981
|
return /* @__PURE__ */ jsx(
|
|
2690
2982
|
"button",
|
|
2691
2983
|
{
|
|
@@ -2708,7 +3000,7 @@ const MemoizedMarkdownBlock = memo(
|
|
|
2708
3000
|
return /* @__PURE__ */ jsx(
|
|
2709
3001
|
ReactMarkdown,
|
|
2710
3002
|
{
|
|
2711
|
-
remarkPlugins: [remarkGfm, remarkBreaks],
|
|
3003
|
+
remarkPlugins: [remarkGfm, remarkBreaks, remarkFilePathLinks],
|
|
2712
3004
|
components,
|
|
2713
3005
|
children: content
|
|
2714
3006
|
}
|
|
@@ -2735,15 +3027,24 @@ function MarkdownComponent({
|
|
|
2735
3027
|
const blockId = id ?? generatedId;
|
|
2736
3028
|
const blocks = useMemo(() => parseMarkdownIntoBlocks(children), [children]);
|
|
2737
3029
|
const [filePreview, setFilePreview] = useState({ status: "idle" });
|
|
2738
|
-
const
|
|
2739
|
-
|
|
2740
|
-
|
|
3030
|
+
const navigate = useNavigate();
|
|
3031
|
+
const openDirectoryInExplorer = useCallback((path) => {
|
|
3032
|
+
const workspacePath = toWorkspacePath(path);
|
|
3033
|
+
useFileExplorerState.getState().navigateTo(workspacePath);
|
|
3034
|
+
setFilePreview({ status: "idle" });
|
|
3035
|
+
navigate({ to: "/files" });
|
|
3036
|
+
}, [navigate]);
|
|
3037
|
+
const onOpenFilePreview = useCallback((path) => {
|
|
3038
|
+
const resolvedPath = normalizeClickedPath(path);
|
|
3039
|
+
if (isDirectoryPathHeuristic(resolvedPath)) {
|
|
3040
|
+
openDirectoryInExplorer(resolvedPath);
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
setFilePreview({ status: "loading", path: resolvedPath });
|
|
3044
|
+
}, [openDirectoryInExplorer]);
|
|
2741
3045
|
const defaultComponents = useMemo(
|
|
2742
|
-
() => createDefaultComponents(
|
|
2743
|
-
|
|
2744
|
-
inlineFilePreviewEnabled
|
|
2745
|
-
),
|
|
2746
|
-
[inlineFilePreviewEnabled]
|
|
3046
|
+
() => createDefaultComponents(onOpenFilePreview),
|
|
3047
|
+
[onOpenFilePreview]
|
|
2747
3048
|
);
|
|
2748
3049
|
const mergedComponents = useMemo(
|
|
2749
3050
|
() => ({ ...defaultComponents, ...components || {} }),
|
|
@@ -2758,6 +3059,10 @@ function MarkdownComponent({
|
|
|
2758
3059
|
}).then(async (response) => {
|
|
2759
3060
|
const payload = await response.json().catch(() => ({}));
|
|
2760
3061
|
if (!response.ok) {
|
|
3062
|
+
if (isDirectoryError(payload.code, payload.message)) {
|
|
3063
|
+
openDirectoryInExplorer(path);
|
|
3064
|
+
return;
|
|
3065
|
+
}
|
|
2761
3066
|
const error = fileErrorMessageFromResponse(response.status, payload.code);
|
|
2762
3067
|
setFilePreview({ status: "error", path, message: error });
|
|
2763
3068
|
return;
|
|
@@ -2779,17 +3084,33 @@ function MarkdownComponent({
|
|
|
2779
3084
|
setFilePreview({ status: "error", path, message: "Failed to load file preview" });
|
|
2780
3085
|
});
|
|
2781
3086
|
return () => controller.abort();
|
|
2782
|
-
}, [filePreview]);
|
|
3087
|
+
}, [filePreview, openDirectoryInExplorer]);
|
|
2783
3088
|
const previewOpen = filePreview.status !== "idle";
|
|
2784
3089
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2785
|
-
/* @__PURE__ */ jsx(
|
|
2786
|
-
|
|
3090
|
+
/* @__PURE__ */ jsx(
|
|
3091
|
+
"div",
|
|
2787
3092
|
{
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
3093
|
+
className: cn("flex min-w-0 max-w-full flex-col gap-2 overflow-x-hidden", className),
|
|
3094
|
+
onClickCapture: (event) => {
|
|
3095
|
+
const target = event.target;
|
|
3096
|
+
const anchor = target?.closest?.('a[href^="openclaw-file://"]');
|
|
3097
|
+
if (!anchor) return;
|
|
3098
|
+
const filePath = markdownHrefToFilePath(anchor.getAttribute("href") ?? void 0);
|
|
3099
|
+
if (!filePath) return;
|
|
3100
|
+
event.preventDefault();
|
|
3101
|
+
event.stopPropagation();
|
|
3102
|
+
onOpenFilePreview(filePath);
|
|
3103
|
+
},
|
|
3104
|
+
children: blocks.map((block, index) => /* @__PURE__ */ jsx(
|
|
3105
|
+
MemoizedMarkdownBlock,
|
|
3106
|
+
{
|
|
3107
|
+
content: block,
|
|
3108
|
+
components: mergedComponents
|
|
3109
|
+
},
|
|
3110
|
+
`${blockId}-block-${index}`
|
|
3111
|
+
))
|
|
3112
|
+
}
|
|
3113
|
+
),
|
|
2793
3114
|
/* @__PURE__ */ jsx(
|
|
2794
3115
|
DialogRoot,
|
|
2795
3116
|
{
|
|
@@ -2809,21 +3130,28 @@ function MarkdownComponent({
|
|
|
2809
3130
|
{
|
|
2810
3131
|
to: "/files",
|
|
2811
3132
|
onClick: () => {
|
|
2812
|
-
|
|
3133
|
+
const p = filePreview.status !== "idle" ? toWorkspacePath(filePreview.path) : "";
|
|
2813
3134
|
if (p) {
|
|
2814
|
-
const prefixes = ["/root/clawd/", "/root/"];
|
|
2815
|
-
for (const prefix of prefixes) {
|
|
2816
|
-
if (p.startsWith(prefix)) {
|
|
2817
|
-
p = "/" + p.slice(prefix.length);
|
|
2818
|
-
break;
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
3135
|
const dir = p.includes("/") ? p.slice(0, p.lastIndexOf("/")) || "/" : "/";
|
|
2822
3136
|
useFileExplorerState.getState().navigateTo(dir);
|
|
2823
3137
|
}
|
|
2824
3138
|
setFilePreview({ status: "idle" });
|
|
2825
3139
|
},
|
|
2826
|
-
children: "Open in
|
|
3140
|
+
children: "Open in Explorer"
|
|
3141
|
+
}
|
|
3142
|
+
) }),
|
|
3143
|
+
filePreview.status !== "idle" && /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: /* @__PURE__ */ jsx(
|
|
3144
|
+
Link,
|
|
3145
|
+
{
|
|
3146
|
+
to: "/files",
|
|
3147
|
+
onClick: () => {
|
|
3148
|
+
const p = filePreview.status !== "idle" ? toWorkspacePath(filePreview.path) : "";
|
|
3149
|
+
if (p) {
|
|
3150
|
+
useFileExplorerState.getState().openInEditor(p);
|
|
3151
|
+
}
|
|
3152
|
+
setFilePreview({ status: "idle" });
|
|
3153
|
+
},
|
|
3154
|
+
children: "Open in Editor"
|
|
2827
3155
|
}
|
|
2828
3156
|
) }),
|
|
2829
3157
|
/* @__PURE__ */ jsx(DialogClose, { children: "Close" })
|
|
@@ -2858,7 +3186,7 @@ function MessageContent({
|
|
|
2858
3186
|
...props
|
|
2859
3187
|
}) {
|
|
2860
3188
|
const classNames = cn(
|
|
2861
|
-
"rounded-[12px] break-words whitespace-normal min-w-0",
|
|
3189
|
+
"rounded-[12px] break-words whitespace-normal min-w-0 max-w-full overflow-x-hidden",
|
|
2862
3190
|
className
|
|
2863
3191
|
);
|
|
2864
3192
|
return markdown ? /* @__PURE__ */ jsx(Markdown, { className: classNames, ...props, children }) : /* @__PURE__ */ jsx("div", { className: classNames, ...props, children });
|
|
@@ -3183,7 +3511,9 @@ function MessageItemComponent({
|
|
|
3183
3511
|
aggregatedSearchSources,
|
|
3184
3512
|
wrapperRef,
|
|
3185
3513
|
wrapperClassName,
|
|
3186
|
-
wrapperScrollMarginTop
|
|
3514
|
+
wrapperScrollMarginTop,
|
|
3515
|
+
messageDomId,
|
|
3516
|
+
highlighted = false
|
|
3187
3517
|
}) {
|
|
3188
3518
|
const { settings } = useChatSettings$1();
|
|
3189
3519
|
const role = message.role || "assistant";
|
|
@@ -3199,18 +3529,21 @@ function MessageItemComponent({
|
|
|
3199
3529
|
"div",
|
|
3200
3530
|
{
|
|
3201
3531
|
ref: wrapperRef,
|
|
3532
|
+
id: messageDomId,
|
|
3533
|
+
"data-message-id": messageDomId,
|
|
3202
3534
|
style: {
|
|
3203
3535
|
contentVisibility: "auto",
|
|
3204
3536
|
containIntrinsicSize: "auto 120px",
|
|
3205
3537
|
...typeof wrapperScrollMarginTop === "number" ? { scrollMarginTop: `${wrapperScrollMarginTop}px` } : void 0
|
|
3206
3538
|
},
|
|
3207
3539
|
className: cn(
|
|
3208
|
-
"group flex flex-col gap-1",
|
|
3540
|
+
"opencami-message-item group mx-auto flex w-full max-w-[var(--opencami-chat-width)] flex-col gap-1 py-[var(--opencami-msg-padding-y)]",
|
|
3209
3541
|
wrapperClassName,
|
|
3542
|
+
highlighted && "opencami-message-highlight",
|
|
3210
3543
|
isUser ? "items-end" : "items-start"
|
|
3211
3544
|
),
|
|
3212
3545
|
children: [
|
|
3213
|
-
thinking && settings.showReasoningBlocks && /* @__PURE__ */ jsx("div", { className: "w-full max-w-[
|
|
3546
|
+
thinking && settings.showReasoningBlocks && /* @__PURE__ */ jsx("div", { className: "w-full max-w-[var(--opencami-chat-width)]", children: /* @__PURE__ */ jsx(Thinking, { content: thinking }) }),
|
|
3214
3547
|
images.length > 0 && /* @__PURE__ */ jsx("div", { className: cn(
|
|
3215
3548
|
"flex flex-wrap gap-2 mb-2",
|
|
3216
3549
|
isUser ? "justify-end" : "justify-start"
|
|
@@ -3225,19 +3558,19 @@ function MessageItemComponent({
|
|
|
3225
3558
|
},
|
|
3226
3559
|
idx
|
|
3227
3560
|
)) }),
|
|
3228
|
-
/* @__PURE__ */ jsx(Message, { className: cn(isUser ? "flex-row-reverse" : ""), children: /* @__PURE__ */ jsx(
|
|
3561
|
+
/* @__PURE__ */ jsx(Message, { className: cn("min-w-0 max-w-full", isUser ? "flex-row-reverse" : ""), children: /* @__PURE__ */ jsx(
|
|
3229
3562
|
MessageContent,
|
|
3230
3563
|
{
|
|
3231
3564
|
markdown: !isUser,
|
|
3232
3565
|
className: cn(
|
|
3233
|
-
"text-primary-900 opencami-text-size",
|
|
3234
|
-
|
|
3566
|
+
"text-primary-900 opencami-text-size min-w-0 max-w-full",
|
|
3567
|
+
isUser ? "opencami-message-user bg-primary-100 px-4 py-[var(--opencami-user-bubble-py)] max-w-[85%]" : "opencami-message-assistant bg-transparent w-full",
|
|
3235
3568
|
!isUser && isStreaming && "stream-fade-in"
|
|
3236
3569
|
),
|
|
3237
3570
|
children: text
|
|
3238
3571
|
}
|
|
3239
3572
|
) }),
|
|
3240
|
-
hasToolCalls && settings.showToolMessages && /* @__PURE__ */ jsx("div", { className: "w-full max-w-[
|
|
3573
|
+
hasToolCalls && settings.showToolMessages && /* @__PURE__ */ jsx("div", { className: "mt-2 flex w-full min-w-0 max-w-[var(--opencami-chat-width)] flex-col gap-3 overflow-x-hidden", children: toolCalls.map((toolCall) => {
|
|
3241
3574
|
const resultMessage = toolCall.id ? toolResultsByCallId?.get(toolCall.id) : void 0;
|
|
3242
3575
|
const toolPart = mapToolCallToToolPart(toolCall, resultMessage);
|
|
3243
3576
|
return /* @__PURE__ */ jsx(
|
|
@@ -3249,7 +3582,7 @@ function MessageItemComponent({
|
|
|
3249
3582
|
toolCall.id || toolCall.name
|
|
3250
3583
|
);
|
|
3251
3584
|
}) }),
|
|
3252
|
-
searchSources.length > 0 && /* @__PURE__ */ jsx("div", { className: "w-full max-w-[
|
|
3585
|
+
searchSources.length > 0 && /* @__PURE__ */ jsx("div", { className: "w-full max-w-[var(--opencami-chat-width)]", children: /* @__PURE__ */ jsx(SearchSourcesBadge, { sources: searchSources }) }),
|
|
3253
3586
|
!hasToolCalls && /* @__PURE__ */ jsx(
|
|
3254
3587
|
MessageActionsBar,
|
|
3255
3588
|
{
|
|
@@ -3275,6 +3608,8 @@ function areMessagesEqual(prevProps, nextProps) {
|
|
|
3275
3608
|
if (prevProps.wrapperScrollMarginTop !== nextProps.wrapperScrollMarginTop) {
|
|
3276
3609
|
return false;
|
|
3277
3610
|
}
|
|
3611
|
+
if (prevProps.messageDomId !== nextProps.messageDomId) return false;
|
|
3612
|
+
if (prevProps.highlighted !== nextProps.highlighted) return false;
|
|
3278
3613
|
if ((prevProps.message.role || "assistant") !== (nextProps.message.role || "assistant")) {
|
|
3279
3614
|
return false;
|
|
3280
3615
|
}
|
|
@@ -3854,12 +4189,12 @@ function ChatContainerShell({
|
|
|
3854
4189
|
/* @__PURE__ */ jsx(
|
|
3855
4190
|
ScrollAreaViewport,
|
|
3856
4191
|
{
|
|
3857
|
-
className: "relative will-change-transform",
|
|
4192
|
+
className: "relative will-change-transform overflow-x-hidden",
|
|
3858
4193
|
ref: viewportRef,
|
|
3859
4194
|
...viewportProps
|
|
3860
4195
|
}
|
|
3861
4196
|
),
|
|
3862
|
-
/* @__PURE__ */ jsx("div", { className: "relative mx-auto w-full max-w-full px-5 sm:max-w-[768px]
|
|
4197
|
+
/* @__PURE__ */ jsx("div", { className: "relative mx-auto w-full min-w-0 max-w-full px-5 sm:max-w-[768px]", children: /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute bottom-10 right-10 z-50", children: /* @__PURE__ */ jsx(ScrollButton, { scrollRef }) }) }),
|
|
3863
4198
|
/* @__PURE__ */ jsx(ScrollAreaScrollbar, { orientation: "vertical", children: /* @__PURE__ */ jsx(ScrollAreaThumb, {}) }),
|
|
3864
4199
|
/* @__PURE__ */ jsx(ScrollAreaCorner, {})
|
|
3865
4200
|
]
|
|
@@ -3897,7 +4232,7 @@ function ChatContainerPortal({
|
|
|
3897
4232
|
}) {
|
|
3898
4233
|
if (!viewportNode) return null;
|
|
3899
4234
|
return createPortal(
|
|
3900
|
-
/* @__PURE__ */ jsx("div", { className: "relative flex w-full flex-col", children }),
|
|
4235
|
+
/* @__PURE__ */ jsx("div", { className: "relative flex w-full min-w-0 max-w-full flex-col overflow-x-hidden", children }),
|
|
3901
4236
|
viewportNode
|
|
3902
4237
|
);
|
|
3903
4238
|
}
|
|
@@ -3946,9 +4281,9 @@ function ChatContainerContent({
|
|
|
3946
4281
|
return /* @__PURE__ */ jsx(
|
|
3947
4282
|
"div",
|
|
3948
4283
|
{
|
|
3949
|
-
className: cn("flex w-full flex-col min-h-full", className),
|
|
4284
|
+
className: cn("flex w-full min-w-0 max-w-full flex-col min-h-full overflow-x-hidden", className),
|
|
3950
4285
|
...props,
|
|
3951
|
-
children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-full px-2 md:px-5 sm:max-w-[768px]
|
|
4286
|
+
children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full min-w-0 max-w-full px-2 md:px-5 sm:max-w-[768px] flex flex-col flex-1 min-h-full overflow-x-hidden", children: /* @__PURE__ */ jsx("div", { className: "flex min-w-0 max-w-full flex-col space-y-3 md:space-y-6", children }) })
|
|
3952
4287
|
}
|
|
3953
4288
|
);
|
|
3954
4289
|
}
|
|
@@ -4022,13 +4357,15 @@ function ChatMessageListComponent({
|
|
|
4022
4357
|
pinGroupMinHeight,
|
|
4023
4358
|
headerHeight,
|
|
4024
4359
|
contentStyle,
|
|
4025
|
-
onFollowUpClick
|
|
4360
|
+
onFollowUpClick,
|
|
4361
|
+
jumpToMessageId
|
|
4026
4362
|
}) {
|
|
4027
4363
|
const anchorRef = useRef(null);
|
|
4028
4364
|
const lastUserRef = useRef(null);
|
|
4029
4365
|
const programmaticScroll = useRef(false);
|
|
4030
4366
|
const prevPinRef = useRef(pinToTop);
|
|
4031
4367
|
const prevUserIndexRef = useRef(void 0);
|
|
4368
|
+
const [highlightedMessageId, setHighlightedMessageId] = useState(null);
|
|
4032
4369
|
const displayMessages = useMemo(() => {
|
|
4033
4370
|
return messages.filter((msg) => msg.role !== "toolResult");
|
|
4034
4371
|
}, [messages]);
|
|
@@ -4145,13 +4482,25 @@ function ChatMessageListComponent({
|
|
|
4145
4482
|
}, 0);
|
|
4146
4483
|
}
|
|
4147
4484
|
}, [loading, displayMessages.length, sessionKey, pinToTop, lastUserIndex]);
|
|
4485
|
+
useEffect(() => {
|
|
4486
|
+
if (!jumpToMessageId || loading) return;
|
|
4487
|
+
const target = document.getElementById(`message-${jumpToMessageId}`);
|
|
4488
|
+
if (!target) return;
|
|
4489
|
+
target.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
4490
|
+
setHighlightedMessageId(jumpToMessageId);
|
|
4491
|
+
const timer = window.setTimeout(() => {
|
|
4492
|
+
setHighlightedMessageId((prev) => prev === jumpToMessageId ? null : prev);
|
|
4493
|
+
}, 1800);
|
|
4494
|
+
return () => window.clearTimeout(timer);
|
|
4495
|
+
}, [jumpToMessageId, loading, displayMessages]);
|
|
4148
4496
|
return (
|
|
4149
4497
|
// mt-2 is to fix the prompt-input cut off
|
|
4150
4498
|
/* @__PURE__ */ jsx(MemoizedChatContainerRoot, { className: "flex-1 min-h-0 -mb-4", children: /* @__PURE__ */ jsxs(ChatContainerContent, { className: "pt-6", style: contentStyle, children: [
|
|
4151
4499
|
notice && noticePosition === "start" ? notice : null,
|
|
4152
4500
|
empty && !notice ? emptyState ?? /* @__PURE__ */ jsx("div", { "aria-hidden": true }) : hasGroup ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4153
4501
|
displayMessages.slice(0, groupStartIndex).map((chatMessage, index) => {
|
|
4154
|
-
const
|
|
4502
|
+
const messageId = typeof chatMessage.id === "string" ? chatMessage.id : void 0;
|
|
4503
|
+
const messageKey = messageId || index;
|
|
4155
4504
|
const forceActionsVisible = typeof lastAssistantIndex === "number" && index === lastAssistantIndex;
|
|
4156
4505
|
const isLastAssistant = typeof lastAssistantIndex === "number" && index === lastAssistantIndex;
|
|
4157
4506
|
const hasToolCalls = chatMessage.role === "assistant" && getToolCallsFromMessage(chatMessage).length > 0;
|
|
@@ -4163,7 +4512,9 @@ function ChatMessageListComponent({
|
|
|
4163
4512
|
forceActionsVisible,
|
|
4164
4513
|
isStreaming: isLastAssistant && isStreaming,
|
|
4165
4514
|
isLastAssistant,
|
|
4166
|
-
aggregatedSearchSources: isLastAssistant ? aggregatedSearchSources : void 0
|
|
4515
|
+
aggregatedSearchSources: isLastAssistant ? aggregatedSearchSources : void 0,
|
|
4516
|
+
messageDomId: messageId ? `message-${messageId}` : void 0,
|
|
4517
|
+
highlighted: highlightedMessageId === messageId
|
|
4167
4518
|
},
|
|
4168
4519
|
messageKey
|
|
4169
4520
|
);
|
|
@@ -4171,12 +4522,13 @@ function ChatMessageListComponent({
|
|
|
4171
4522
|
/* @__PURE__ */ jsxs(
|
|
4172
4523
|
"div",
|
|
4173
4524
|
{
|
|
4174
|
-
className: "flex flex-col
|
|
4175
|
-
style: { minHeight: `${Math.max(0, pinGroupMinHeight
|
|
4525
|
+
className: "flex flex-col gap-[var(--opencami-msg-gap)]",
|
|
4526
|
+
style: { minHeight: `${Math.max(0, pinGroupMinHeight)}px` },
|
|
4176
4527
|
children: [
|
|
4177
4528
|
displayMessages.slice(groupStartIndex).map((chatMessage, index) => {
|
|
4178
4529
|
const realIndex = groupStartIndex + index;
|
|
4179
|
-
const
|
|
4530
|
+
const messageId = typeof chatMessage.id === "string" ? chatMessage.id : void 0;
|
|
4531
|
+
const messageKey = messageId || realIndex;
|
|
4180
4532
|
const forceActionsVisible = typeof lastAssistantIndex === "number" && realIndex === lastAssistantIndex;
|
|
4181
4533
|
const isLastAssistant = typeof lastAssistantIndex === "number" && realIndex === lastAssistantIndex;
|
|
4182
4534
|
const wrapperRef = realIndex === lastUserIndex ? lastUserRef : void 0;
|
|
@@ -4194,7 +4546,9 @@ function ChatMessageListComponent({
|
|
|
4194
4546
|
aggregatedSearchSources: isLastAssistant ? aggregatedSearchSources : void 0,
|
|
4195
4547
|
wrapperRef,
|
|
4196
4548
|
wrapperClassName,
|
|
4197
|
-
wrapperScrollMarginTop
|
|
4549
|
+
wrapperScrollMarginTop,
|
|
4550
|
+
messageDomId: messageId ? `message-${messageId}` : void 0,
|
|
4551
|
+
highlighted: highlightedMessageId === messageId
|
|
4198
4552
|
},
|
|
4199
4553
|
messageKey
|
|
4200
4554
|
);
|
|
@@ -4213,7 +4567,8 @@ function ChatMessageListComponent({
|
|
|
4213
4567
|
)
|
|
4214
4568
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4215
4569
|
displayMessages.map((chatMessage, index) => {
|
|
4216
|
-
const
|
|
4570
|
+
const messageId = typeof chatMessage.id === "string" ? chatMessage.id : void 0;
|
|
4571
|
+
const messageKey = messageId || index;
|
|
4217
4572
|
const forceActionsVisible = typeof lastAssistantIndex === "number" && index === lastAssistantIndex;
|
|
4218
4573
|
const isLastAssistant = typeof lastAssistantIndex === "number" && index === lastAssistantIndex;
|
|
4219
4574
|
const hasToolCalls = chatMessage.role === "assistant" && getToolCallsFromMessage(chatMessage).length > 0;
|
|
@@ -4225,7 +4580,9 @@ function ChatMessageListComponent({
|
|
|
4225
4580
|
forceActionsVisible,
|
|
4226
4581
|
isStreaming: isLastAssistant && isStreaming,
|
|
4227
4582
|
isLastAssistant,
|
|
4228
|
-
aggregatedSearchSources: isLastAssistant ? aggregatedSearchSources : void 0
|
|
4583
|
+
aggregatedSearchSources: isLastAssistant ? aggregatedSearchSources : void 0,
|
|
4584
|
+
messageDomId: messageId ? `message-${messageId}` : void 0,
|
|
4585
|
+
highlighted: highlightedMessageId === messageId
|
|
4229
4586
|
},
|
|
4230
4587
|
messageKey
|
|
4231
4588
|
);
|
|
@@ -4250,7 +4607,7 @@ function ChatMessageListComponent({
|
|
|
4250
4607
|
);
|
|
4251
4608
|
}
|
|
4252
4609
|
function areChatMessageListEqual(prev, next) {
|
|
4253
|
-
return prev.messages === next.messages && prev.loading === next.loading && prev.empty === next.empty && prev.emptyState === next.emptyState && prev.notice === next.notice && prev.noticePosition === next.noticePosition && prev.waitingForResponse === next.waitingForResponse && prev.isStreaming === next.isStreaming && prev.sessionKey === next.sessionKey && prev.pinToTop === next.pinToTop && prev.pinGroupMinHeight === next.pinGroupMinHeight && prev.headerHeight === next.headerHeight && prev.contentStyle === next.contentStyle && prev.onFollowUpClick === next.onFollowUpClick;
|
|
4610
|
+
return prev.messages === next.messages && prev.loading === next.loading && prev.empty === next.empty && prev.emptyState === next.emptyState && prev.notice === next.notice && prev.noticePosition === next.noticePosition && prev.waitingForResponse === next.waitingForResponse && prev.isStreaming === next.isStreaming && prev.sessionKey === next.sessionKey && prev.pinToTop === next.pinToTop && prev.pinGroupMinHeight === next.pinGroupMinHeight && prev.headerHeight === next.headerHeight && prev.contentStyle === next.contentStyle && prev.onFollowUpClick === next.onFollowUpClick && prev.jumpToMessageId === next.jumpToMessageId;
|
|
4254
4611
|
}
|
|
4255
4612
|
const MemoizedChatMessageList = memo(
|
|
4256
4613
|
ChatMessageListComponent,
|
|
@@ -5584,7 +5941,7 @@ function ChatComposerComponent({
|
|
|
5584
5941
|
return /* @__PURE__ */ jsxs(
|
|
5585
5942
|
"div",
|
|
5586
5943
|
{
|
|
5587
|
-
className: "mx-auto w-full max-w-
|
|
5944
|
+
className: "mx-auto w-full max-w-[var(--opencami-chat-width)] px-2 md:px-5 relative pb-1 md:pb-3",
|
|
5588
5945
|
ref: wrapperRef,
|
|
5589
5946
|
onDragOver: handleDragOver,
|
|
5590
5947
|
onDragLeave: handleDragLeave,
|
|
@@ -5687,7 +6044,7 @@ function MessageStatus({
|
|
|
5687
6044
|
onAction,
|
|
5688
6045
|
className
|
|
5689
6046
|
}) {
|
|
5690
|
-
return /* @__PURE__ */ jsx("div", { className: cn("w-full max-w-[
|
|
6047
|
+
return /* @__PURE__ */ jsx("div", { className: cn("w-full max-w-[var(--opencami-chat-width)]", className), children: /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs("div", { className: "w-full rounded-xl border border-primary-200 bg-primary-50 p-4 text-primary-900", children: [
|
|
5691
6048
|
/* @__PURE__ */ jsx("div", { className: "text-balance font-medium", children: title }),
|
|
5692
6049
|
/* @__PURE__ */ jsx("div", { className: "mt-2 text-pretty text-primary-700", children: description }),
|
|
5693
6050
|
detail ? /* @__PURE__ */ jsx("div", { className: "mt-2 text-xs text-primary-600", children: detail }) : null,
|
|
@@ -6265,15 +6622,16 @@ function useSwipeGesture(options) {
|
|
|
6265
6622
|
};
|
|
6266
6623
|
}
|
|
6267
6624
|
const KeyboardShortcutsDialog = lazy(
|
|
6268
|
-
() => import("./keyboard-shortcuts-dialog-
|
|
6625
|
+
() => import("./keyboard-shortcuts-dialog-CsNP85q8.js").then((m) => ({
|
|
6269
6626
|
default: m.KeyboardShortcutsDialog
|
|
6270
6627
|
}))
|
|
6271
6628
|
);
|
|
6272
6629
|
const SearchDialog = lazy(
|
|
6273
|
-
() => import("./search-dialog-
|
|
6630
|
+
() => import("./search-dialog-Bz4Cu0KW.js").then((m) => ({
|
|
6274
6631
|
default: m.SearchDialog
|
|
6275
6632
|
}))
|
|
6276
6633
|
);
|
|
6634
|
+
const SEARCH_JUMP_TARGET_KEY = "opencami-search-jump-target";
|
|
6277
6635
|
function ChatScreen({
|
|
6278
6636
|
activeFriendlyId,
|
|
6279
6637
|
isNewChat = false,
|
|
@@ -6296,6 +6654,7 @@ function ChatScreen({
|
|
|
6296
6654
|
const [showShortcutsHelp, setShowShortcutsHelp] = useState(false);
|
|
6297
6655
|
const [showSearchDialog, setShowSearchDialog] = useState(false);
|
|
6298
6656
|
const [searchMode, setSearchMode] = useState("global");
|
|
6657
|
+
const [searchJumpMessageId, setSearchJumpMessageId] = useState(null);
|
|
6299
6658
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
6300
6659
|
const thinkingLevel = useThinkingLevelStore((state) => state.level);
|
|
6301
6660
|
const inputRef = useRef(null);
|
|
@@ -6608,6 +6967,10 @@ function ChatScreen({
|
|
|
6608
6967
|
useEffect(() => {
|
|
6609
6968
|
const resetKey = isNewChat ? "new" : activeFriendlyId;
|
|
6610
6969
|
if (!resetKey) return;
|
|
6970
|
+
streamStop();
|
|
6971
|
+
stopStream();
|
|
6972
|
+
lastAssistantSignature.current = "";
|
|
6973
|
+
setIsStreaming(false);
|
|
6611
6974
|
if (pendingStartRef.current) {
|
|
6612
6975
|
pendingStartRef.current = false;
|
|
6613
6976
|
return;
|
|
@@ -6617,13 +6980,34 @@ function ChatScreen({
|
|
|
6617
6980
|
setPinToTop(true);
|
|
6618
6981
|
return;
|
|
6619
6982
|
}
|
|
6620
|
-
streamStop();
|
|
6621
|
-
stopStream();
|
|
6622
|
-
lastAssistantSignature.current = "";
|
|
6623
6983
|
setWaitingForResponse(false);
|
|
6624
6984
|
setPinToTop(false);
|
|
6625
|
-
setIsStreaming(false);
|
|
6626
6985
|
}, [activeFriendlyId, isNewChat, streamStop, stopStream]);
|
|
6986
|
+
useEffect(() => {
|
|
6987
|
+
if (typeof window === "undefined") return;
|
|
6988
|
+
try {
|
|
6989
|
+
const raw = sessionStorage.getItem(SEARCH_JUMP_TARGET_KEY);
|
|
6990
|
+
if (!raw) {
|
|
6991
|
+
setSearchJumpMessageId(null);
|
|
6992
|
+
return;
|
|
6993
|
+
}
|
|
6994
|
+
const parsed = JSON.parse(raw);
|
|
6995
|
+
const isStale = typeof parsed.at === "number" && Date.now() - parsed.at > 5 * 60 * 1e3;
|
|
6996
|
+
if (isStale) {
|
|
6997
|
+
sessionStorage.removeItem(SEARCH_JUMP_TARGET_KEY);
|
|
6998
|
+
setSearchJumpMessageId(null);
|
|
6999
|
+
return;
|
|
7000
|
+
}
|
|
7001
|
+
if (parsed.friendlyId === activeFriendlyId && typeof parsed.messageId === "string" && parsed.messageId.length > 0) {
|
|
7002
|
+
setSearchJumpMessageId(parsed.messageId);
|
|
7003
|
+
sessionStorage.removeItem(SEARCH_JUMP_TARGET_KEY);
|
|
7004
|
+
return;
|
|
7005
|
+
}
|
|
7006
|
+
setSearchJumpMessageId(null);
|
|
7007
|
+
} catch {
|
|
7008
|
+
setSearchJumpMessageId(null);
|
|
7009
|
+
}
|
|
7010
|
+
}, [activeFriendlyId]);
|
|
6627
7011
|
useLayoutEffect(() => {
|
|
6628
7012
|
if (isNewChat) return;
|
|
6629
7013
|
const pending = consumePendingSend(
|
|
@@ -6945,7 +7329,7 @@ function ChatScreen({
|
|
|
6945
7329
|
{
|
|
6946
7330
|
className: cn(
|
|
6947
7331
|
"h-full overflow-hidden",
|
|
6948
|
-
isMobile ? "relative" : "grid grid-cols-[
|
|
7332
|
+
isMobile ? "relative" : "grid grid-cols-[auto_minmax(0,1fr)]"
|
|
6949
7333
|
),
|
|
6950
7334
|
children: [
|
|
6951
7335
|
hideUi ? null : isMobile ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -6964,7 +7348,7 @@ function ChatScreen({
|
|
|
6964
7348
|
"div",
|
|
6965
7349
|
{
|
|
6966
7350
|
className: cn(
|
|
6967
|
-
"fixed inset-y-0 left-0 z-50 w-[
|
|
7351
|
+
"fixed inset-y-0 left-0 z-50 w-[var(--opencami-sidebar-width)] transition-transform duration-150 safe-area-top",
|
|
6968
7352
|
isSidebarCollapsed ? "-translate-x-full" : "translate-x-0"
|
|
6969
7353
|
),
|
|
6970
7354
|
...sidebarCloseSwipeHandlers,
|
|
@@ -6975,7 +7359,7 @@ function ChatScreen({
|
|
|
6975
7359
|
/* @__PURE__ */ jsxs(
|
|
6976
7360
|
"main",
|
|
6977
7361
|
{
|
|
6978
|
-
className: "flex flex-col h-full min-h-0",
|
|
7362
|
+
className: "flex flex-col h-full min-h-0 min-w-0 overflow-x-hidden",
|
|
6979
7363
|
ref: mainRef,
|
|
6980
7364
|
...sidebarSwipeHandlers,
|
|
6981
7365
|
children: [
|
|
@@ -7006,7 +7390,8 @@ function ChatScreen({
|
|
|
7006
7390
|
pinGroupMinHeight,
|
|
7007
7391
|
headerHeight,
|
|
7008
7392
|
contentStyle: stableContentStyle,
|
|
7009
|
-
onFollowUpClick: handleFollowUpClick
|
|
7393
|
+
onFollowUpClick: handleFollowUpClick,
|
|
7394
|
+
jumpToMessageId: searchJumpMessageId
|
|
7010
7395
|
}
|
|
7011
7396
|
),
|
|
7012
7397
|
/* @__PURE__ */ jsx(
|
|
@@ -7044,9 +7429,25 @@ function ChatScreen({
|
|
|
7044
7429
|
mode: searchMode,
|
|
7045
7430
|
onJumpToMessage: (result) => {
|
|
7046
7431
|
setShowSearchDialog(false);
|
|
7047
|
-
if (result.friendlyId)
|
|
7048
|
-
|
|
7432
|
+
if (!result.friendlyId) return;
|
|
7433
|
+
if (result.messageId && result.friendlyId === activeFriendlyId) {
|
|
7434
|
+
setSearchJumpMessageId(result.messageId);
|
|
7435
|
+
return;
|
|
7436
|
+
}
|
|
7437
|
+
if (result.messageId && typeof window !== "undefined") {
|
|
7438
|
+
try {
|
|
7439
|
+
sessionStorage.setItem(
|
|
7440
|
+
SEARCH_JUMP_TARGET_KEY,
|
|
7441
|
+
JSON.stringify({
|
|
7442
|
+
friendlyId: result.friendlyId,
|
|
7443
|
+
messageId: result.messageId,
|
|
7444
|
+
at: Date.now()
|
|
7445
|
+
})
|
|
7446
|
+
);
|
|
7447
|
+
} catch {
|
|
7448
|
+
}
|
|
7049
7449
|
}
|
|
7450
|
+
navigate({ to: "/chat/$sessionKey", params: { sessionKey: result.friendlyId } });
|
|
7050
7451
|
}
|
|
7051
7452
|
}
|
|
7052
7453
|
) })
|