import { formatProviderSkillDisplayName, resolveProviderSkillSourceKind, type ProviderSkillSourceKind, } from "@t3tools/client-runtime/providerSkills"; import { type ProjectEntry, type ProviderDriverKind, type ServerProviderSkill, type ServerProviderSlashCommand, } from "@t3tools/contracts"; import { BlocksIcon, FolderIcon, PackageIcon, SettingsIcon, UserRoundIcon, type LucideIcon, } from "lucide-react"; import { memo, useLayoutEffect, useRef } from "react"; import { type ComposerSlashCommand, type ComposerTriggerKind } from "../../composer-logic"; import { cn } from "~/lib/utils"; import { Badge } from "../ui/badge"; import { Command, CommandGroup, CommandItem, CommandList } from "../ui/command"; import { PierreEntryIcon } from "./PierreEntryIcon"; import { ComposerBanner } from "./ComposerBanner"; export type ComposerCommandItem = | { id: string; type: "path"; path: string; pathKind: ProjectEntry["kind"]; label: string; description: string; } | { id: string; type: "slash-command"; command: ComposerSlashCommand; label: string; description: string; } | { id: string; type: "provider-slash-command"; provider: ProviderDriverKind; command: ServerProviderSlashCommand; label: string; description: string; } | { id: string; type: "skill"; provider: ProviderDriverKind; skill: ServerProviderSkill; label: string; description: string; }; export const ComposerCommandMenu = memo(function ComposerCommandMenu(props: { items: ComposerCommandItem[]; resolvedTheme: "light" | "dark"; isLoading: boolean; triggerKind: ComposerTriggerKind | null; emptyStateText?: string; activeItemId: string | null; onHighlightedItemChange: (itemId: string | null) => void; onSelect: (item: ComposerCommandItem) => void; }) { const listRef = useRef(null); useLayoutEffect(() => { if (!props.activeItemId || !listRef.current) return; const el = listRef.current.querySelector( `[data-composer-item-id="${CSS.escape(props.activeItemId)}"]`, ); el?.scrollIntoView({ block: "nearest" }); }, [props.activeItemId]); return ( { props.onHighlightedItemChange( typeof highlightedValue === "string" ? highlightedValue : null, ); }} > {props.items.length > 0 ? ( {props.items.map((item) => ( ))} ) : (

{props.isLoading ? props.triggerKind === "skill" ? "Searching workspace skills..." : "Searching workspace files..." : (props.emptyStateText ?? (props.triggerKind === "skill" ? "No skills found. Try / to browse provider commands." : props.triggerKind === "path" ? "No matching files or folders." : "No matching command."))}

)}
); }); const ComposerCommandMenuItem = memo(function ComposerCommandMenuItem(props: { item: ComposerCommandItem; triggerKind: ComposerTriggerKind | null; resolvedTheme: "light" | "dark"; isActive: boolean; onHighlight: (itemId: string | null) => void; onSelect: (item: ComposerCommandItem) => void; }) { const skillSourceKind = props.item.type === "skill" ? resolveProviderSkillSourceKind(props.item.skill) : null; const isSlashSkill = props.triggerKind === "slash-command" && props.item.type === "skill" ? props.item.skill : null; return ( { if (!props.isActive) props.onHighlight(props.item.id); }} onMouseDown={(event) => { event.preventDefault(); }} onClick={() => { props.onSelect(props.item); }} > {props.item.type === "path" ? ( ) : null} {isSlashSkill ? ( <> /skill: {formatProviderSkillDisplayName(isSlashSkill)} ) : ( props.item.label )} {props.item.description} {skillSourceKind ? ( ) : null} ); }); const SKILL_SOURCE_ICON_BY_KIND: Record = { app: BlocksIcon, repo: FolderIcon, project: FolderIcon, personal: UserRoundIcon, system: SettingsIcon, other: PackageIcon, }; const SKILL_SOURCE_LABEL_BY_KIND: Record = { app: "App", repo: "Repo", project: "Project", personal: "Personal", system: "System", other: "Provider", }; function SkillSourceBadge(props: { kind: ProviderSkillSourceKind; showSkillSuffix: boolean }) { const Icon = SKILL_SOURCE_ICON_BY_KIND[props.kind]; return ( ); }