import { LexicalComposer, type InitialConfigType } from "@lexical/react/LexicalComposer";import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";import { ContentEditable } from "@lexical/react/LexicalContentEditable";import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";import { PlainTextPlugin } from "@lexical/react/LexicalPlainTextPlugin";import { type ServerProviderSkill } from "@t3tools/contracts";import { serializeComposerFileLink } from "@t3tools/shared/composerTrigger";import { $applyNodeReplacement, $createRangeSelectionFromDom, $createRangeSelection, $getSelection, $setSelection, $isElementNode, $isLineBreakNode, $isRangeSelection, $isTextNode, $createLineBreakNode, $createParagraphNode, $createTextNode, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_DOWN_COMMAND, KEY_ENTER_COMMAND, KEY_TAB_COMMAND, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, KEY_BACKSPACE_COMMAND, BLUR_COMMAND, FOCUS_COMMAND, $getRoot, $getNodeByKey, HISTORY_MERGE_TAG, HISTORY_PUSH_TAG, SKIP_DOM_SELECTION_TAG, DecoratorNode, type ElementNode, type LexicalNode, type SerializedLexicalNode, type EditorState, type NodeKey, type Spread,} from "lexical";import { createContext, use, useCallback, useEffect, useEffectEvent, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState,} from "react"; import { clampCollapsedComposerCursor, collapseExpandedComposerCursor, expandCollapsedComposerCursor, isCollapsedCursorAdjacentToInlineToken,} from "~/composer-logic";import { selectionTouchesMentionBoundary, splitPromptIntoComposerSegments,} from "~/composer-editor-mentions";import { INLINE_TERMINAL_CONTEXT_PLACEHOLDER, type TerminalContextDraft,} from "~/lib/terminalContext";import { cn, isMacPlatform } from "~/lib/utils";import { basenameOfPath } from "~/pierre-icons";import { COMPOSER_INLINE_CHIP_DECORATOR_CLASS_NAME, COMPOSER_INLINE_CHIP_ICON_CLASS_NAME, COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME, COMPOSER_INLINE_SKILL_CHIP_CLASS_NAME, SKILL_CHIP_ICON_SVG,} from "./composerInlineChip";import { FILE_TAG_CHIP_CLASS_NAME, FileTagChipContent } from "./chat/FileTagChip";import { ComposerPendingTerminalContextChip } from "./chat/ComposerPendingTerminalContexts";import { getTimelinePageScrollKey } from "./chat/pageScrollController";import { formatProviderSkillDisplayName } from "@t3tools/client-runtime/providerSkills";import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";import { registerComposerInlineTokenPaste } from "./composerInlineTokenPaste";import { didComposerSelectionChangeVisibly } from "./composerSelection";import { $consumeComposerCitationCommentRequest, $createComposerCitationNode, ComposerCitationCommentContext, ComposerCitationNode, type ComposerCitationCommentRequest, type ComposerCitationCommentTarget,} from "./ComposerCitationNode"; const COMPOSER_EDITOR_HMR_KEY = `composer-editor-${Math.random().toString(36).slice(2)}`;const SURROUND_SYMBOLS: [string, string][] = [ ["(", ")"], ["[", "]"], ["{", "}"], ["'", "'"], ['"', '"'], ["“", "”"], ["`", "`"], ["<", ">"], ["«", "»"], ["*", "*"], ["_", "_"],];const SURROUND_SYMBOLS_MAP = new Map<string, string>(SURROUND_SYMBOLS);const BACKTICK_SURROUND_CLOSE_SYMBOL = SURROUND_SYMBOLS_MAP.get("`") ?? null; type SerializedComposerMentionNode = Spread< { path: string; source?: string; type: "composer-mention"; version: 1; }, SerializedLexicalNode>; type SerializedComposerSkillNode = Spread< { skillName: string; skillLabel?: string; skillDescription?: string; type: "composer-skill"; version: 1; }, SerializedLexicalNode>; type SerializedComposerTerminalContextNode = Spread< { context: TerminalContextDraft; type: "composer-terminal-context"; version: 1; }, SerializedLexicalNode>; const ComposerTerminalContextActionsContext = createContext<{ onRemoveTerminalContext: (contextId: string) => void;}>({ onRemoveTerminalContext: () => {},}); function ComposerMentionDecorator(props: { path: string }) { const theme = resolvedThemeFromDocument(); const chip = ( <span className={FILE_TAG_CHIP_CLASS_NAME} contentEditable={false} spellCheck={false} data-composer-mention-chip="true" > <FileTagChipContent path={props.path} label={basenameOfPath(props.path)} theme={theme} /> </span> ); return ( <Tooltip> <TooltipTrigger render={chip} /> <TooltipPopup side="top" className="max-w-120 whitespace-normal leading-tight wrap-anywhere"> {props.path} </TooltipPopup> </Tooltip> );} class ComposerMentionNode extends DecoratorNode<React.ReactElement> { __path: string; __source: string; static override getType(): string { return "composer-mention"; } static override clone(node: ComposerMentionNode): ComposerMentionNode { return new ComposerMentionNode(node.__path, node.__source, node.__key); } static override importJSON(serializedNode: SerializedComposerMentionNode): ComposerMentionNode { return $createComposerMentionNode(serializedNode.path, serializedNode.source).updateFromJSON( serializedNode, ); } constructor(path: string, source = serializeComposerFileLink(path), key?: NodeKey) { super(key); this.__path = path; this.__source = source; } override exportJSON(): SerializedComposerMentionNode { return { ...super.exportJSON(), path: this.__path, source: this.__source, type: "composer-mention", version: 1, }; } override createDOM(): HTMLElement { const dom = document.createElement("span"); dom.className = COMPOSER_INLINE_CHIP_DECORATOR_CLASS_NAME; return dom; } override updateDOM(): false { return false; } override getTextContent(): string { return this.__source; } override isInline(): true { return true; } override decorate(): React.ReactElement { return <ComposerMentionDecorator path={this.__path} />; }} function $createComposerMentionNode(path: string, source?: string): ComposerMentionNode { return $applyNodeReplacement(new ComposerMentionNode(path, source));} function resolveSkillDescription( skill: Pick<ServerProviderSkill, "shortDescription" | "description">,): string | null { const shortDescription = skill.shortDescription?.trim(); if (shortDescription) { return shortDescription; } const description = skill.description?.trim(); return description || null;} type ComposerSkillMetadata = { label: string; description: string | null;}; function skillMetadataByName( skills: ReadonlyArray<ServerProviderSkill>,): ReadonlyMap<string, ComposerSkillMetadata> { return new Map( skills.map((skill) => [ skill.name, { label: formatProviderSkillDisplayName(skill), description: resolveSkillDescription(skill), }, ]), );} function ComposerSkillDecorator(props: { skillLabel: string; skillDescription: string | null }) { const chip = ( <span className={COMPOSER_INLINE_SKILL_CHIP_CLASS_NAME} contentEditable={false} spellCheck={false} data-composer-skill-chip="true" > <span aria-hidden="true" className={COMPOSER_INLINE_CHIP_ICON_CLASS_NAME} dangerouslySetInnerHTML={{ __html: SKILL_CHIP_ICON_SVG }} /> <span className={COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME}>{props.skillLabel}</span> </span> ); if (!props.skillDescription) { return chip; } return ( <Tooltip> <TooltipTrigger render={chip} /> <TooltipPopup side="top" className="max-w-120 whitespace-normal leading-tight"> {props.skillDescription} </TooltipPopup> </Tooltip> );} class ComposerSkillNode extends DecoratorNode<React.ReactElement> { __skillName: string; __skillLabel: string; __skillDescription: string | null; static override getType(): string { return "composer-skill"; } static override clone(node: ComposerSkillNode): ComposerSkillNode { return new ComposerSkillNode( node.__skillName, node.__skillLabel, node.__skillDescription, node.__key, ); } static override importJSON(serializedNode: SerializedComposerSkillNode): ComposerSkillNode { return $createComposerSkillNode( serializedNode.skillName, serializedNode.skillLabel ?? serializedNode.skillName, serializedNode.skillDescription ?? null, ).updateFromJSON(serializedNode); } constructor( skillName: string, skillLabel: string, skillDescription: string | null, key?: NodeKey, ) { super(key); const normalizedSkillName = skillName.startsWith("$") ? skillName.slice(1) : skillName; this.__skillName = normalizedSkillName; this.__skillLabel = skillLabel; this.__skillDescription = skillDescription; } override exportJSON(): SerializedComposerSkillNode { return { ...super.exportJSON(), skillName: this.__skillName, skillLabel: this.__skillLabel, ...(this.__skillDescription ? { skillDescription: this.__skillDescription } : {}), type: "composer-skill", version: 1, }; } override createDOM(): HTMLElement { const dom = document.createElement("span"); dom.className = COMPOSER_INLINE_CHIP_DECORATOR_CLASS_NAME; return dom; } override updateDOM(): false { return false; } override getTextContent(): string { return `$${this.__skillName}`; } override isInline(): true { return true; } override decorate(): React.ReactElement { return ( <ComposerSkillDecorator skillLabel={this.__skillLabel} skillDescription={this.__skillDescription} /> ); }} function $createComposerSkillNode( skillName: string, skillLabel: string, skillDescription: string | null,): ComposerSkillNode { return $applyNodeReplacement(new ComposerSkillNode(skillName, skillLabel, skillDescription));} function ComposerTerminalContextDecorator(props: { context: TerminalContextDraft }) { return <ComposerPendingTerminalContextChip context={props.context} />;} class ComposerTerminalContextNode extends DecoratorNode<React.ReactElement> { __context: TerminalContextDraft; static override getType(): string { return "composer-terminal-context"; } static override clone(node: ComposerTerminalContextNode): ComposerTerminalContextNode { return new ComposerTerminalContextNode(node.__context, node.__key); } static override importJSON( serializedNode: SerializedComposerTerminalContextNode, ): ComposerTerminalContextNode { return $createComposerTerminalContextNode(serializedNode.context); } constructor(context: TerminalContextDraft, key?: NodeKey) { super(key); this.__context = context; } override exportJSON(): SerializedComposerTerminalContextNode { return { ...super.exportJSON(), context: this.__context, type: "composer-terminal-context", version: 1, }; } override createDOM(): HTMLElement { const dom = document.createElement("span"); dom.className = COMPOSER_INLINE_CHIP_DECORATOR_CLASS_NAME; return dom; } override updateDOM(): false { return false; } override getTextContent(): string { return INLINE_TERMINAL_CONTEXT_PLACEHOLDER; } override isInline(): true { return true; } override decorate(): React.ReactElement { return <ComposerTerminalContextDecorator context={this.__context} />; }} function $createComposerTerminalContextNode( context: TerminalContextDraft,): ComposerTerminalContextNode { return $applyNodeReplacement(new ComposerTerminalContextNode(context));} type ComposerInlineTokenNode = | ComposerMentionNode | ComposerSkillNode | ComposerCitationNode | ComposerTerminalContextNode; function isComposerInlineTokenNode(candidate: unknown): candidate is ComposerInlineTokenNode { return ( candidate instanceof ComposerMentionNode || candidate instanceof ComposerSkillNode || candidate instanceof ComposerCitationNode || candidate instanceof ComposerTerminalContextNode );} function resolvedThemeFromDocument(): "light" | "dark" { return document.documentElement.classList.contains("dark") ? "dark" : "light";} function terminalContextSignature(contexts: ReadonlyArray<TerminalContextDraft>): string { return contexts .map((context) => [ context.id, context.threadId, context.terminalId, context.terminalLabel, context.lineStart, context.lineEnd, context.createdAt, context.text, ].join("\u001f"), ) .join("\u001e");} function skillSignature(skills: ReadonlyArray<ServerProviderSkill>): string { return skills .map((skill) => [ skill.name, skill.displayName ?? "", skill.shortDescription ?? "", skill.description ?? "", skill.path, skill.scope ?? "", skill.enabled ? "1" : "0", ].join("\u001f"), ) .join("\u001e");} function clampExpandedCursor(value: string, cursor: number): number {Lines 1–500 of 2134. Load more
import { LexicalComposer, type InitialConfigType } from "@lexical/react/LexicalComposer"; import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"; import { ContentEditable } from "@lexical/react/LexicalContentEditable"; import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary"; import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin"; import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin"; import { PlainTextPlugin } from "@lexical/react/LexicalPlainTextPlugin"; import { type ServerProviderSkill } from "@t3tools/contracts"; import { serializeComposerFileLink } from "@t3tools/shared/composerTrigger"; import { $applyNodeReplacement, $createRangeSelectionFromDom, $createRangeSelection, $getSelection, $setSelection, $isElementNode, $isLineBreakNode, $isRangeSelection, $isTextNode, $createLineBreakNode, $createParagraphNode, $createTextNode, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_DOWN_COMMAND, KEY_ENTER_COMMAND, KEY_TAB_COMMAND, COMMAND_PRIORITY_HIGH, COMMAND_PRIORITY_LOW, KEY_BACKSPACE_COMMAND, BLUR_COMMAND, FOCUS_COMMAND, $getRoot, $getNodeByKey, HISTORY_MERGE_TAG, HISTORY_PUSH_TAG, SKIP_DOM_SELECTION_TAG, DecoratorNode, type ElementNode, type LexicalNode, type SerializedLexicalNode, type EditorState, type NodeKey, type Spread, } from "lexical"; import { createContext, use, useCallback, useEffect, useEffectEvent, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, } from "react"; import { clampCollapsedComposerCursor, collapseExpandedComposerCursor, expandCollapsedComposerCursor, isCollapsedCursorAdjacentToInlineToken, } from "~/composer-logic"; import { selectionTouchesMentionBoundary, splitPromptIntoComposerSegments, } from "~/composer-editor-mentions"; import { INLINE_TERMINAL_CONTEXT_PLACEHOLDER, type TerminalContextDraft, } from "~/lib/terminalContext"; import { cn, isMacPlatform } from "~/lib/utils"; import { basenameOfPath } from "~/pierre-icons"; import { COMPOSER_INLINE_CHIP_DECORATOR_CLASS_NAME, COMPOSER_INLINE_CHIP_ICON_CLASS_NAME, COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME, COMPOSER_INLINE_SKILL_CHIP_CLASS_NAME, SKILL_CHIP_ICON_SVG, } from "./composerInlineChip"; import { FILE_TAG_CHIP_CLASS_NAME, FileTagChipContent } from "./chat/FileTagChip"; import { ComposerPendingTerminalContextChip } from "./chat/ComposerPendingTerminalContexts"; import { getTimelinePageScrollKey } from "./chat/pageScrollController"; import { formatProviderSkillDisplayName } from "@t3tools/client-runtime/providerSkills"; import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; import { registerComposerInlineTokenPaste } from "./composerInlineTokenPaste"; import { didComposerSelectionChangeVisibly } from "./composerSelection"; import { $consumeComposerCitationCommentRequest, $createComposerCitationNode, ComposerCitationCommentContext, ComposerCitationNode, type ComposerCitationCommentRequest, type ComposerCitationCommentTarget, } from "./ComposerCitationNode"; const COMPOSER_EDITOR_HMR_KEY = `composer-editor-${Math.random().toString(36).slice(2)}`; const SURROUND_SYMBOLS: [string, string][] = [ ["(", ")"], ["[", "]"], ["{", "}"], ["'", "'"], ['"', '"'], ["“", "”"], ["`", "`"], ["<", ">"], ["«", "»"], ["*", "*"], ["_", "_"], ]; const SURROUND_SYMBOLS_MAP = new Map<string, string>(SURROUND_SYMBOLS); const BACKTICK_SURROUND_CLOSE_SYMBOL = SURROUND_SYMBOLS_MAP.get("`") ?? null; type SerializedComposerMentionNode = Spread< { path: string; source?: string; type: "composer-mention"; version: 1; }, SerializedLexicalNode >; type SerializedComposerSkillNode = Spread< { skillName: string; skillLabel?: string; skillDescription?: string; type: "composer-skill"; version: 1; }, SerializedLexicalNode >; type SerializedComposerTerminalContextNode = Spread< { context: TerminalContextDraft; type: "composer-terminal-context"; version: 1; }, SerializedLexicalNode >; const ComposerTerminalContextActionsContext = createContext<{ onRemoveTerminalContext: (contextId: string) => void; }>({ onRemoveTerminalContext: () => {}, }); function ComposerMentionDecorator(props: { path: string }) { const theme = resolvedThemeFromDocument(); const chip = ( <span className={FILE_TAG_CHIP_CLASS_NAME} contentEditable={false} spellCheck={false} data-composer-mention-chip="true" > <FileTagChipContent path={props.path} label={basenameOfPath(props.path)} theme={theme} /> </span> ); return ( <Tooltip> <TooltipTrigger render={chip} /> <TooltipPopup side="top" className="max-w-120 whitespace-normal leading-tight wrap-anywhere"> {props.path} </TooltipPopup> </Tooltip> ); } class ComposerMentionNode extends DecoratorNode<React.ReactElement> { __path: string; __source: string; static override getType(): string { return "composer-mention"; } static override clone(node: ComposerMentionNode): ComposerMentionNode { return new ComposerMentionNode(node.__path, node.__source, node.__key); } static override importJSON(serializedNode: SerializedComposerMentionNode): ComposerMentionNode { return $createComposerMentionNode(serializedNode.path, serializedNode.source).updateFromJSON( serializedNode, ); } constructor(path: string, source = serializeComposerFileLink(path), key?: NodeKey) { super(key); this.__path = path; this.__source = source; } override exportJSON(): SerializedComposerMentionNode { return { ...super.exportJSON(), path: this.__path, source: this.__source, type: "composer-mention", version: 1, }; } override createDOM(): HTMLElement { const dom = document.createElement("span"); dom.className = COMPOSER_INLINE_CHIP_DECORATOR_CLASS_NAME; return dom; } override updateDOM(): false { return false; } override getTextContent(): string { return this.__source; } override isInline(): true { return true; } override decorate(): React.ReactElement { return <ComposerMentionDecorator path={this.__path} />; } } function $createComposerMentionNode(path: string, source?: string): ComposerMentionNode { return $applyNodeReplacement(new ComposerMentionNode(path, source)); } function resolveSkillDescription( skill: Pick<ServerProviderSkill, "shortDescription" | "description">, ): string | null { const shortDescription = skill.shortDescription?.trim(); if (shortDescription) { return shortDescription; } const description = skill.description?.trim(); return description || null; } type ComposerSkillMetadata = { label: string; description: string | null; }; function skillMetadataByName( skills: ReadonlyArray<ServerProviderSkill>, ): ReadonlyMap<string, ComposerSkillMetadata> { return new Map( skills.map((skill) => [ skill.name, { label: formatProviderSkillDisplayName(skill), description: resolveSkillDescription(skill), }, ]), ); } function ComposerSkillDecorator(props: { skillLabel: string; skillDescription: string | null }) { const chip = ( <span className={COMPOSER_INLINE_SKILL_CHIP_CLASS_NAME} contentEditable={false} spellCheck={false} data-composer-skill-chip="true" > <span aria-hidden="true" className={COMPOSER_INLINE_CHIP_ICON_CLASS_NAME} dangerouslySetInnerHTML={{ __html: SKILL_CHIP_ICON_SVG }} /> <span className={COMPOSER_INLINE_CHIP_LABEL_CLASS_NAME}>{props.skillLabel}</span> </span> ); if (!props.skillDescription) { return chip; } return ( <Tooltip> <TooltipTrigger render={chip} /> <TooltipPopup side="top" className="max-w-120 whitespace-normal leading-tight"> {props.skillDescription} </TooltipPopup> </Tooltip> ); } class ComposerSkillNode extends DecoratorNode<React.ReactElement> { __skillName: string; __skillLabel: string; __skillDescription: string | null; static override getType(): string { return "composer-skill"; } static override clone(node: ComposerSkillNode): ComposerSkillNode { return new ComposerSkillNode( node.__skillName, node.__skillLabel, node.__skillDescription, node.__key, ); } static override importJSON(serializedNode: SerializedComposerSkillNode): ComposerSkillNode { return $createComposerSkillNode( serializedNode.skillName, serializedNode.skillLabel ?? serializedNode.skillName, serializedNode.skillDescription ?? null, ).updateFromJSON(serializedNode); } constructor( skillName: string, skillLabel: string, skillDescription: string | null, key?: NodeKey, ) { super(key); const normalizedSkillName = skillName.startsWith("$") ? skillName.slice(1) : skillName; this.__skillName = normalizedSkillName; this.__skillLabel = skillLabel; this.__skillDescription = skillDescription; } override exportJSON(): SerializedComposerSkillNode { return { ...super.exportJSON(), skillName: this.__skillName, skillLabel: this.__skillLabel, ...(this.__skillDescription ? { skillDescription: this.__skillDescription } : {}), type: "composer-skill", version: 1, }; } override createDOM(): HTMLElement { const dom = document.createElement("span"); dom.className = COMPOSER_INLINE_CHIP_DECORATOR_CLASS_NAME; return dom; } override updateDOM(): false { return false; } override getTextContent(): string { return `$${this.__skillName}`; } override isInline(): true { return true; } override decorate(): React.ReactElement { return ( <ComposerSkillDecorator skillLabel={this.__skillLabel} skillDescription={this.__skillDescription} /> ); } } function $createComposerSkillNode( skillName: string, skillLabel: string, skillDescription: string | null, ): ComposerSkillNode { return $applyNodeReplacement(new ComposerSkillNode(skillName, skillLabel, skillDescription)); } function ComposerTerminalContextDecorator(props: { context: TerminalContextDraft }) { return <ComposerPendingTerminalContextChip context={props.context} />; } class ComposerTerminalContextNode extends DecoratorNode<React.ReactElement> { __context: TerminalContextDraft; static override getType(): string { return "composer-terminal-context"; } static override clone(node: ComposerTerminalContextNode): ComposerTerminalContextNode { return new ComposerTerminalContextNode(node.__context, node.__key); } static override importJSON( serializedNode: SerializedComposerTerminalContextNode, ): ComposerTerminalContextNode { return $createComposerTerminalContextNode(serializedNode.context); } constructor(context: TerminalContextDraft, key?: NodeKey) { super(key); this.__context = context; } override exportJSON(): SerializedComposerTerminalContextNode { return { ...super.exportJSON(), context: this.__context, type: "composer-terminal-context", version: 1, }; } override createDOM(): HTMLElement { const dom = document.createElement("span"); dom.className = COMPOSER_INLINE_CHIP_DECORATOR_CLASS_NAME; return dom; } override updateDOM(): false { return false; } override getTextContent(): string { return INLINE_TERMINAL_CONTEXT_PLACEHOLDER; } override isInline(): true { return true; } override decorate(): React.ReactElement { return <ComposerTerminalContextDecorator context={this.__context} />; } } function $createComposerTerminalContextNode( context: TerminalContextDraft, ): ComposerTerminalContextNode { return $applyNodeReplacement(new ComposerTerminalContextNode(context)); } type ComposerInlineTokenNode = | ComposerMentionNode | ComposerSkillNode | ComposerCitationNode | ComposerTerminalContextNode; function isComposerInlineTokenNode(candidate: unknown): candidate is ComposerInlineTokenNode { return ( candidate instanceof ComposerMentionNode || candidate instanceof ComposerSkillNode || candidate instanceof ComposerCitationNode || candidate instanceof ComposerTerminalContextNode ); } function resolvedThemeFromDocument(): "light" | "dark" { return document.documentElement.classList.contains("dark") ? "dark" : "light"; } function terminalContextSignature(contexts: ReadonlyArray<TerminalContextDraft>): string { return contexts .map((context) => [ context.id, context.threadId, context.terminalId, context.terminalLabel, context.lineStart, context.lineEnd, context.createdAt, context.text, ].join("\u001f"), ) .join("\u001e"); } function skillSignature(skills: ReadonlyArray<ServerProviderSkill>): string { return skills .map((skill) => [ skill.name, skill.displayName ?? "", skill.shortDescription ?? "", skill.description ?? "", skill.path, skill.scope ?? "", skill.enabled ? "1" : "0", ].join("\u001f"), ) .join("\u001e"); } function clampExpandedCursor(value: string, cursor: number): number {