@tangle-network/agent-app 0.46.3 → 0.46.4
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/assistant/index.js +2 -1
- package/dist/assistant/index.js.map +1 -1
- package/dist/chunk-RLOHIX5Y.js +36 -0
- package/dist/chunk-RLOHIX5Y.js.map +1 -0
- package/dist/{chunk-RZ6MYWMJ.js → chunk-YTEUZXX2.js} +169 -43
- package/dist/chunk-YTEUZXX2.js.map +1 -0
- package/dist/mention-editor-GVLG3W7C.js +521 -0
- package/dist/mention-editor-GVLG3W7C.js.map +1 -0
- package/dist/teams/drizzle/invitations-schema.d.ts +1 -1
- package/dist/teams/drizzle/schema.d.ts +1 -1
- package/dist/web-react/chat-composer.d.ts +24 -4
- package/dist/web-react/index.d.ts +1 -0
- package/dist/web-react/index.js +5 -1
- package/dist/web-react/mention-boundaries.d.ts +33 -0
- package/dist/web-react/mention-editor.d.ts +84 -0
- package/dist/web-react/mention-list.d.ts +35 -0
- package/dist/web-react/mention-pill.d.ts +10 -0
- package/dist/web-react/mention-serialize.d.ts +44 -0
- package/dist/web-react/use-file-mentions.d.ts +28 -14
- package/package.json +32 -1
- package/dist/chunk-RZ6MYWMJ.js.map +0 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/web-react/mention-pill.ts
|
|
2
|
+
var MENTION_PILL_CLASS = "rounded-md bg-primary/10 px-1 py-0.5 font-medium text-primary";
|
|
3
|
+
|
|
4
|
+
// src/web-react/class-names.ts
|
|
5
|
+
function joinClasses(...parts) {
|
|
6
|
+
const kept = [];
|
|
7
|
+
for (const part of parts) {
|
|
8
|
+
if (typeof part !== "string") continue;
|
|
9
|
+
const trimmed = part.trim();
|
|
10
|
+
if (trimmed.length > 0) kept.push(trimmed);
|
|
11
|
+
}
|
|
12
|
+
return kept.join(" ");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// src/web-react/mention-boundaries.ts
|
|
16
|
+
var PATH_CONTINUATION_CHAR = /[\p{L}\p{M}\p{N}._\-/]/u;
|
|
17
|
+
var WORD_CHAR = /[\p{L}\p{M}\p{N}]/u;
|
|
18
|
+
function charBefore(text, index) {
|
|
19
|
+
if (index <= 0) return void 0;
|
|
20
|
+
return Array.from(text.slice(Math.max(0, index - 2), index)).pop();
|
|
21
|
+
}
|
|
22
|
+
function charAt(text, index) {
|
|
23
|
+
if (index >= text.length) return void 0;
|
|
24
|
+
const codePoint = text.codePointAt(index);
|
|
25
|
+
return codePoint === void 0 ? void 0 : String.fromCodePoint(codePoint);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
MENTION_PILL_CLASS,
|
|
30
|
+
joinClasses,
|
|
31
|
+
PATH_CONTINUATION_CHAR,
|
|
32
|
+
WORD_CHAR,
|
|
33
|
+
charBefore,
|
|
34
|
+
charAt
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=chunk-RLOHIX5Y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/web-react/mention-pill.ts","../src/web-react/class-names.ts","../src/web-react/mention-boundaries.ts"],"sourcesContent":["/**\n * Visual contract for a rendered mention pill. The TipTap extension in\n * `mention-editor.tsx` styles its inline atom node with this, and any other\n * surface that renders a resolved mention (e.g. a sent-message transcript)\n * uses the same constant so the two stay one visual contract instead of\n * silently drifting apart. Kept in its own module (no TipTap import) so\n * importing it never pulls the lazily-loaded editor chunk into a consumer's\n * bundle.\n */\nexport const MENTION_PILL_CLASS = 'rounded-md bg-primary/10 px-1 py-0.5 font-medium text-primary'\n","/**\n * One class-attribute join for this subpath.\n *\n * The pattern it replaces is `` `base ${className ?? ''}` ``, which emits\n * `class=\"base \"` for every caller that passes nothing: a trailing separator in\n * the DOM, in every snapshot, and in every assertion that compares the attribute\n * instead of searching it. Interpolating an absent value is the defect — the\n * fix is to never build the attribute by interpolation.\n */\nexport function joinClasses(...parts: ReadonlyArray<string | false | null | undefined>): string {\n const kept: string[] = []\n for (const part of parts) {\n if (typeof part !== 'string') continue\n const trimmed = part.trim()\n if (trimmed.length > 0) kept.push(trimmed)\n }\n return kept.join(' ')\n}\n","/**\n * The one boundary vocabulary for reading `@<path>` mention tokens out of\n * plain text. Two inverse readings share it — the transcript segmenter\n * (`chat-mentions.ts`) and editor-pill restore (`mention-serialize.ts`) — and\n * they must agree, or a token one accepts the other mangles. Kept OUT of the\n * `/web-react` barrel on purpose: these are internals of the grammar, not\n * public API.\n */\n\n/** A character that could plausibly continue the SAME path/filename past a\n * matched token. Without this lookahead a mention of `@a/b.md` would match\n * inside the unrelated `@a/b.md.bak` and split it mid-filename.\n *\n * Unicode-aware because the wire validator (`validateSandboxMentionPath`)\n * deliberately ALLOWS non-ASCII paths — in-box filenames are arbitrary. An\n * ASCII-only class here would accept input the readers then mangle.\n * `\\p{M}` keeps DECOMPOSED filenames whole: without it, a combining accent\n * (`a` + U+0301) reads as a boundary and splits the name after its base\n * letter. */\nexport const PATH_CONTINUATION_CHAR = /[\\p{L}\\p{M}\\p{N}._\\-/]/u\n\n/** A character that, immediately BEFORE an `@`, means the `@` is part of a\n * longer token (an email local part, a handle) rather than a mention start.\n * Unicode-aware for the same reasons, combining marks included. */\nexport const WORD_CHAR = /[\\p{L}\\p{M}\\p{N}]/u\n\n/** The full character (code point) ENDING just before `index`, or undefined\n * at the start. Indexing `text[index - 1]` hands a lone UTF-16 surrogate to\n * the Unicode-aware classes above, which then misread every astral letter —\n * boundary checks must see whole characters. `index` must be a code-point\n * boundary (both callers derive it from `@` positions and id lengths, which\n * are). */\nexport function charBefore(text: string, index: number): string | undefined {\n if (index <= 0) return undefined\n return Array.from(text.slice(Math.max(0, index - 2), index)).pop()\n}\n\n/** The full character (code point) starting at `index`, or undefined past the\n * end — same surrogate rationale and precondition as {@link charBefore}. */\nexport function charAt(text: string, index: number): string | undefined {\n if (index >= text.length) return undefined\n const codePoint = text.codePointAt(index)\n return codePoint === undefined ? undefined : String.fromCodePoint(codePoint)\n}\n"],"mappings":";AASO,IAAM,qBAAqB;;;ACA3B,SAAS,eAAe,OAAiE;AAC9F,QAAM,OAAiB,CAAC;AACxB,aAAW,QAAQ,OAAO;AACxB,QAAI,OAAO,SAAS,SAAU;AAC9B,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,QAAQ,SAAS,EAAG,MAAK,KAAK,OAAO;AAAA,EAC3C;AACA,SAAO,KAAK,KAAK,GAAG;AACtB;;;ACEO,IAAM,yBAAyB;AAK/B,IAAM,YAAY;AAQlB,SAAS,WAAW,MAAc,OAAmC;AAC1E,MAAI,SAAS,EAAG,QAAO;AACvB,SAAO,MAAM,KAAK,KAAK,MAAM,KAAK,IAAI,GAAG,QAAQ,CAAC,GAAG,KAAK,CAAC,EAAE,IAAI;AACnE;AAIO,SAAS,OAAO,MAAc,OAAmC;AACtE,MAAI,SAAS,KAAK,OAAQ,QAAO;AACjC,QAAM,YAAY,KAAK,YAAY,KAAK;AACxC,SAAO,cAAc,SAAY,SAAY,OAAO,cAAc,SAAS;AAC7E;","names":[]}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PATH_CONTINUATION_CHAR,
|
|
3
|
+
WORD_CHAR,
|
|
4
|
+
charAt,
|
|
5
|
+
charBefore,
|
|
6
|
+
joinClasses
|
|
7
|
+
} from "./chunk-RLOHIX5Y.js";
|
|
1
8
|
import {
|
|
2
9
|
stepActivityFlowTrace
|
|
3
10
|
} from "./chunk-FBVLEGEG.js";
|
|
@@ -1412,6 +1419,9 @@ async function streamChatTurn(opts) {
|
|
|
1412
1419
|
|
|
1413
1420
|
// src/web-react/chat-composer.tsx
|
|
1414
1421
|
import {
|
|
1422
|
+
Component,
|
|
1423
|
+
lazy as lazy2,
|
|
1424
|
+
Suspense as Suspense2,
|
|
1415
1425
|
useCallback as useCallback3,
|
|
1416
1426
|
useEffect as useEffect6,
|
|
1417
1427
|
useMemo as useMemo3,
|
|
@@ -1554,6 +1564,56 @@ function useDictation({ onDictate, onError }) {
|
|
|
1554
1564
|
|
|
1555
1565
|
// src/web-react/chat-composer.tsx
|
|
1556
1566
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1567
|
+
function createLazyMentionEditor() {
|
|
1568
|
+
return lazy2(() => import("./mention-editor-GVLG3W7C.js").then((m) => m.loadMentionEditor()));
|
|
1569
|
+
}
|
|
1570
|
+
var MentionEditorBoundary = class extends Component {
|
|
1571
|
+
state = { error: null };
|
|
1572
|
+
static getDerivedStateFromError(error) {
|
|
1573
|
+
return { error };
|
|
1574
|
+
}
|
|
1575
|
+
componentDidCatch() {
|
|
1576
|
+
this.props.onFailed();
|
|
1577
|
+
}
|
|
1578
|
+
render() {
|
|
1579
|
+
if (this.state.error === null) return this.props.children;
|
|
1580
|
+
const message = this.state.error instanceof Error ? this.state.error.message : String(this.state.error);
|
|
1581
|
+
return /* @__PURE__ */ jsxs5(
|
|
1582
|
+
"div",
|
|
1583
|
+
{
|
|
1584
|
+
role: "alert",
|
|
1585
|
+
"data-testid": "composer-mention-editor-error",
|
|
1586
|
+
className: "rounded-xl border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
1587
|
+
children: [
|
|
1588
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-start gap-2", children: [
|
|
1589
|
+
/* @__PURE__ */ jsxs5("span", { className: "min-w-0 flex-1", children: [
|
|
1590
|
+
"The mention input failed to load: ",
|
|
1591
|
+
message
|
|
1592
|
+
] }),
|
|
1593
|
+
/* @__PURE__ */ jsx7(
|
|
1594
|
+
"button",
|
|
1595
|
+
{
|
|
1596
|
+
type: "button",
|
|
1597
|
+
"aria-label": "Retry loading the mention input",
|
|
1598
|
+
onClick: this.props.onRetry,
|
|
1599
|
+
className: "shrink-0 font-medium underline-offset-2 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-destructive/50",
|
|
1600
|
+
children: "Retry"
|
|
1601
|
+
}
|
|
1602
|
+
)
|
|
1603
|
+
] }),
|
|
1604
|
+
this.props.draft.trim() !== "" && /* @__PURE__ */ jsx7(
|
|
1605
|
+
"p",
|
|
1606
|
+
{
|
|
1607
|
+
"data-testid": "composer-error-held-draft",
|
|
1608
|
+
className: "mt-1.5 max-h-20 overflow-y-auto whitespace-pre-wrap rounded-lg border border-destructive/30 bg-card px-2 py-1 text-foreground",
|
|
1609
|
+
children: this.props.draft
|
|
1610
|
+
}
|
|
1611
|
+
)
|
|
1612
|
+
]
|
|
1613
|
+
}
|
|
1614
|
+
);
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1557
1617
|
var IS_APPLE_PLATFORM = typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/i.test(navigator.platform);
|
|
1558
1618
|
function SendGlyph({ className }) {
|
|
1559
1619
|
return /* @__PURE__ */ jsx7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "M22 2 11 13M22 2l-7 20-4-9-9-4 20-7z" }) });
|
|
@@ -1644,6 +1704,7 @@ function ChatComposer({
|
|
|
1644
1704
|
minRows = 2,
|
|
1645
1705
|
maxHeight = DEFAULT_MAX_HEIGHT,
|
|
1646
1706
|
trailing,
|
|
1707
|
+
mention,
|
|
1647
1708
|
slashCommands,
|
|
1648
1709
|
onDictate,
|
|
1649
1710
|
onDictateError,
|
|
@@ -1659,6 +1720,13 @@ function ChatComposer({
|
|
|
1659
1720
|
const textRef = useRef6(text);
|
|
1660
1721
|
textRef.current = text;
|
|
1661
1722
|
const textareaRef = useRef6(null);
|
|
1723
|
+
const richFocusRef = useRef6(null);
|
|
1724
|
+
const registerRichFocus = useCallback3((focus) => {
|
|
1725
|
+
richFocusRef.current = focus;
|
|
1726
|
+
}, []);
|
|
1727
|
+
const [editorEpoch, setEditorEpoch] = useState8(0);
|
|
1728
|
+
const MentionEditor = useMemo3(createLazyMentionEditor, [editorEpoch]);
|
|
1729
|
+
const [editorFailed, setEditorFailed] = useState8(false);
|
|
1662
1730
|
const fileInputRef = useRef6(null);
|
|
1663
1731
|
const folderInputRef = useRef6(null);
|
|
1664
1732
|
const [dragOver, setDragOver] = useState8(false);
|
|
@@ -1730,21 +1798,30 @@ function ChatComposer({
|
|
|
1730
1798
|
const end = Math.min(pending.end, text.length);
|
|
1731
1799
|
el.setSelectionRange(start, end);
|
|
1732
1800
|
}, [text]);
|
|
1801
|
+
const mentionEnabled = mention != null;
|
|
1733
1802
|
useEffect6(() => {
|
|
1734
1803
|
if (!focusShortcut || disabled) return;
|
|
1735
1804
|
function onKeyDown(e) {
|
|
1736
1805
|
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "l") {
|
|
1737
|
-
|
|
1738
|
-
|
|
1806
|
+
if (mentionEnabled) {
|
|
1807
|
+
const focus = richFocusRef.current;
|
|
1808
|
+
if (!focus) return;
|
|
1809
|
+
e.preventDefault();
|
|
1810
|
+
focus();
|
|
1811
|
+
} else {
|
|
1812
|
+
e.preventDefault();
|
|
1813
|
+
textareaRef.current?.focus();
|
|
1814
|
+
}
|
|
1739
1815
|
}
|
|
1740
1816
|
}
|
|
1741
1817
|
document.addEventListener("keydown", onKeyDown);
|
|
1742
1818
|
return () => document.removeEventListener("keydown", onKeyDown);
|
|
1743
|
-
}, [focusShortcut, disabled]);
|
|
1819
|
+
}, [focusShortcut, disabled, mentionEnabled]);
|
|
1744
1820
|
const sendableFiles = canSubmitAttachmentsOnly ? pendingFiles : pendingFiles.filter((f) => f.status === "ready");
|
|
1745
1821
|
const hasSendable = text.trim().length > 0 || sendableFiles.length > 0;
|
|
1746
1822
|
const sendBlockedByStream = isStreaming && !canSubmitWhileBusy;
|
|
1747
|
-
const
|
|
1823
|
+
const editorInputLost = mention != null && editorFailed;
|
|
1824
|
+
const canSend = hasSendable && !sendBlockedByStream && !disabled && !editorInputLost;
|
|
1748
1825
|
const [failedSend, setFailedSend] = useState8(null);
|
|
1749
1826
|
const failSend = useCallback3(
|
|
1750
1827
|
(error, draft, trimmed, parts, caret) => {
|
|
@@ -1789,7 +1866,7 @@ function ChatComposer({
|
|
|
1789
1866
|
);
|
|
1790
1867
|
const send = useCallback3(() => {
|
|
1791
1868
|
const trimmed = text.trim();
|
|
1792
|
-
if (sendBlockedByStream || disabled) return;
|
|
1869
|
+
if (sendBlockedByStream || disabled || editorInputLost) return;
|
|
1793
1870
|
const readyFiles = pendingFiles.filter((f) => f.status === "ready");
|
|
1794
1871
|
const sendable = canSubmitAttachmentsOnly ? pendingFiles : readyFiles;
|
|
1795
1872
|
if (!trimmed && sendable.length === 0) return;
|
|
@@ -1809,6 +1886,7 @@ function ChatComposer({
|
|
|
1809
1886
|
text,
|
|
1810
1887
|
sendBlockedByStream,
|
|
1811
1888
|
disabled,
|
|
1889
|
+
editorInputLost,
|
|
1812
1890
|
canSubmitAttachmentsOnly,
|
|
1813
1891
|
attachmentsNotReadyMessage,
|
|
1814
1892
|
onSendParts,
|
|
@@ -1828,7 +1906,7 @@ function ChatComposer({
|
|
|
1828
1906
|
const slashListId = useId();
|
|
1829
1907
|
const [slashActive, setSlashActive] = useState8(0);
|
|
1830
1908
|
const [slashDismissedFor, setSlashDismissedFor] = useState8(null);
|
|
1831
|
-
const slashToken = slashCommands && slashCommands.length > 0 ? /^\/(\S*)$/.exec(text)?.[1] : void 0;
|
|
1909
|
+
const slashToken = !mention && slashCommands && slashCommands.length > 0 ? /^\/(\S*)$/.exec(text)?.[1] : void 0;
|
|
1832
1910
|
const slashOpen = slashToken !== void 0 && text !== slashDismissedFor;
|
|
1833
1911
|
const slashItems = useMemo3(
|
|
1834
1912
|
() => (slashCommands ?? []).map((command) => ({
|
|
@@ -1926,11 +2004,8 @@ function ChatComposer({
|
|
|
1926
2004
|
if (e.target.files?.length) deliverFiles(Array.from(e.target.files), e.target.files);
|
|
1927
2005
|
e.target.value = "";
|
|
1928
2006
|
};
|
|
1929
|
-
const
|
|
1930
|
-
if (!onAttach) return;
|
|
1931
|
-
const clipboardFiles = e.clipboardData?.files;
|
|
1932
|
-
if (!clipboardFiles || clipboardFiles.length === 0) return;
|
|
1933
|
-
e.preventDefault();
|
|
2007
|
+
const ingestPastedFiles = (clipboardFiles) => {
|
|
2008
|
+
if (!onAttach || clipboardFiles.length === 0) return false;
|
|
1934
2009
|
const { files, nextIndex } = renamePastedImages(
|
|
1935
2010
|
Array.from(clipboardFiles),
|
|
1936
2011
|
pastedImageCount.current,
|
|
@@ -1938,6 +2013,12 @@ function ChatComposer({
|
|
|
1938
2013
|
);
|
|
1939
2014
|
pastedImageCount.current = nextIndex;
|
|
1940
2015
|
deliverFiles(files, clipboardFiles);
|
|
2016
|
+
return true;
|
|
2017
|
+
};
|
|
2018
|
+
const handlePaste = (e) => {
|
|
2019
|
+
const clipboardFiles = e.clipboardData?.files;
|
|
2020
|
+
if (!clipboardFiles || clipboardFiles.length === 0) return;
|
|
2021
|
+
if (ingestPastedFiles(clipboardFiles)) e.preventDefault();
|
|
1941
2022
|
};
|
|
1942
2023
|
const handleFolderChange = (e) => {
|
|
1943
2024
|
if (e.target.files?.length) (onAttachFolder ?? onAttach)?.(e.target.files);
|
|
@@ -1978,6 +2059,7 @@ function ChatComposer({
|
|
|
1978
2059
|
const fileChips = pendingFiles.filter((f) => f.kind !== "folder");
|
|
1979
2060
|
const showAbove = controls != null && controlsPlacement === "above";
|
|
1980
2061
|
const showInline = controls != null && !showAbove;
|
|
2062
|
+
const inputMinHeight = minRows * LINE_HEIGHT + TEXTAREA_PADDING_Y;
|
|
1981
2063
|
return /* @__PURE__ */ jsxs5(
|
|
1982
2064
|
"div",
|
|
1983
2065
|
{
|
|
@@ -2128,22 +2210,79 @@ function ChatComposer({
|
|
|
2128
2210
|
"data-testid": "composer-card",
|
|
2129
2211
|
className: `flex flex-col gap-1.5 rounded-2xl border border-card-edge bg-card px-3 py-2.5 transition focus-within:border-primary/40 focus-within:ring-2 focus-within:ring-primary/15 ${floating ? "shadow-raised" : ""}`,
|
|
2130
2212
|
children: [
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2213
|
+
mention ? (
|
|
2214
|
+
// The editor arrives as a lazy chunk; until it lands, a read-only
|
|
2215
|
+
// textarea with the same metrics holds the layout so the card
|
|
2216
|
+
// doesn't jump. The boundary contains a failed load (e.g. the
|
|
2217
|
+
// missing-peer error) to the input area instead of unmounting the
|
|
2218
|
+
// host's region.
|
|
2219
|
+
/* @__PURE__ */ jsx7(
|
|
2220
|
+
MentionEditorBoundary,
|
|
2221
|
+
{
|
|
2222
|
+
onRetry: () => {
|
|
2223
|
+
setEditorFailed(false);
|
|
2224
|
+
setEditorEpoch((epoch) => epoch + 1);
|
|
2225
|
+
},
|
|
2226
|
+
onFailed: () => setEditorFailed(true),
|
|
2227
|
+
draft: text,
|
|
2228
|
+
children: /* @__PURE__ */ jsx7(
|
|
2229
|
+
Suspense2,
|
|
2230
|
+
{
|
|
2231
|
+
fallback: /* @__PURE__ */ jsx7(
|
|
2232
|
+
"textarea",
|
|
2233
|
+
{
|
|
2234
|
+
rows: minRows,
|
|
2235
|
+
value: text,
|
|
2236
|
+
readOnly: true,
|
|
2237
|
+
disabled: true,
|
|
2238
|
+
placeholder,
|
|
2239
|
+
"aria-label": "Message input",
|
|
2240
|
+
style: { minHeight: inputMinHeight, maxHeight },
|
|
2241
|
+
className: "w-full resize-none bg-transparent px-1.5 py-1 text-base leading-6 text-foreground outline-none placeholder:text-muted-foreground disabled:opacity-50"
|
|
2242
|
+
}
|
|
2243
|
+
),
|
|
2244
|
+
children: /* @__PURE__ */ jsx7(
|
|
2245
|
+
MentionEditor,
|
|
2246
|
+
{
|
|
2247
|
+
value: text,
|
|
2248
|
+
onChange: setText,
|
|
2249
|
+
onSubmit: send,
|
|
2250
|
+
placeholder,
|
|
2251
|
+
disabled,
|
|
2252
|
+
autoFocus,
|
|
2253
|
+
minHeight: inputMinHeight,
|
|
2254
|
+
maxHeight,
|
|
2255
|
+
mention,
|
|
2256
|
+
registerFocus: registerRichFocus,
|
|
2257
|
+
onPasteFiles: onAttach ? ingestPastedFiles : void 0
|
|
2258
|
+
}
|
|
2259
|
+
)
|
|
2260
|
+
}
|
|
2261
|
+
)
|
|
2262
|
+
},
|
|
2263
|
+
editorEpoch
|
|
2264
|
+
)
|
|
2265
|
+
) : (
|
|
2266
|
+
// Focus: `outline-none` is safe because the card above draws the
|
|
2267
|
+
// keyboard indicator through `focus-within:` — one ring for
|
|
2268
|
+
// whichever input mode is mounted.
|
|
2269
|
+
/* @__PURE__ */ jsx7(
|
|
2270
|
+
"textarea",
|
|
2271
|
+
{
|
|
2272
|
+
ref: textareaRef,
|
|
2273
|
+
value: text,
|
|
2274
|
+
onChange: (e) => setText(e.target.value),
|
|
2275
|
+
onKeyDown: handleKeyDown,
|
|
2276
|
+
onPaste: onAttach ? handlePaste : void 0,
|
|
2277
|
+
placeholder,
|
|
2278
|
+
disabled,
|
|
2279
|
+
autoFocus,
|
|
2280
|
+
rows: minRows,
|
|
2281
|
+
style: { minHeight: inputMinHeight, maxHeight },
|
|
2282
|
+
"aria-label": "Message input",
|
|
2283
|
+
className: "w-full resize-none bg-transparent px-1.5 py-1 text-base leading-6 text-foreground outline-none placeholder:text-muted-foreground disabled:opacity-50"
|
|
2284
|
+
}
|
|
2285
|
+
)
|
|
2147
2286
|
),
|
|
2148
2287
|
/* @__PURE__ */ jsxs5("div", { className: "flex items-end gap-2", children: [
|
|
2149
2288
|
onAttach && /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
@@ -2821,8 +2960,6 @@ function useFileMentions(options) {
|
|
|
2821
2960
|
}
|
|
2822
2961
|
|
|
2823
2962
|
// src/web-react/chat-mentions.ts
|
|
2824
|
-
var PATH_CONTINUATION_CHAR = /[\p{L}\p{N}._\-/]/u;
|
|
2825
|
-
var WORD_CHAR = /[\p{L}\p{N}]/u;
|
|
2826
2963
|
function segmentMentionContent(content, parts) {
|
|
2827
2964
|
const matched = /* @__PURE__ */ new Set();
|
|
2828
2965
|
if (!content) return { segments: [], matched };
|
|
@@ -2836,7 +2973,7 @@ function segmentMentionContent(content, parts) {
|
|
|
2836
2973
|
cursor += 1;
|
|
2837
2974
|
continue;
|
|
2838
2975
|
}
|
|
2839
|
-
const prevChar =
|
|
2976
|
+
const prevChar = charBefore(content, cursor);
|
|
2840
2977
|
if (prevChar && WORD_CHAR.test(prevChar)) {
|
|
2841
2978
|
cursor += 1;
|
|
2842
2979
|
continue;
|
|
@@ -2847,7 +2984,7 @@ function segmentMentionContent(content, parts) {
|
|
|
2847
2984
|
continue;
|
|
2848
2985
|
}
|
|
2849
2986
|
const endIdx = cursor + candidate.token.length;
|
|
2850
|
-
const nextChar =
|
|
2987
|
+
const nextChar = charAt(content, endIdx);
|
|
2851
2988
|
if (nextChar && PATH_CONTINUATION_CHAR.test(nextChar)) {
|
|
2852
2989
|
cursor += 1;
|
|
2853
2990
|
continue;
|
|
@@ -5342,17 +5479,6 @@ function CommandPalette({
|
|
|
5342
5479
|
);
|
|
5343
5480
|
}
|
|
5344
5481
|
|
|
5345
|
-
// src/web-react/class-names.ts
|
|
5346
|
-
function joinClasses(...parts) {
|
|
5347
|
-
const kept = [];
|
|
5348
|
-
for (const part of parts) {
|
|
5349
|
-
if (typeof part !== "string") continue;
|
|
5350
|
-
const trimmed = part.trim();
|
|
5351
|
-
if (trimmed.length > 0) kept.push(trimmed);
|
|
5352
|
-
}
|
|
5353
|
-
return kept.join(" ");
|
|
5354
|
-
}
|
|
5355
|
-
|
|
5356
5482
|
// src/web-react/sparkline.tsx
|
|
5357
5483
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5358
5484
|
var DEFAULT_SPARKLINE_WIDTH = 96;
|
|
@@ -6885,4 +7011,4 @@ export {
|
|
|
6885
7011
|
useThinkingSeconds,
|
|
6886
7012
|
ChatMessages
|
|
6887
7013
|
};
|
|
6888
|
-
//# sourceMappingURL=chunk-
|
|
7014
|
+
//# sourceMappingURL=chunk-YTEUZXX2.js.map
|