import { Component, createSignal, createEffect, For, Show, onCleanup } from "solid-js" import type { Agent } from "../types/session" interface FileItem { path: string added?: number removed?: number isGitFile: boolean } type PickerItem = { type: "agent"; agent: Agent } | { type: "file"; file: FileItem } interface UnifiedPickerProps { open: boolean onSelect: (item: PickerItem) => void onClose: () => void agents: Agent[] instanceClient: any searchQuery: string textareaRef?: HTMLTextAreaElement workspaceFolder: string } const UnifiedPicker: Component = (props) => { const [files, setFiles] = createSignal([]) const [filteredAgents, setFilteredAgents] = createSignal([]) const [selectedIndex, setSelectedIndex] = createSignal(0) const [loading, setLoading] = createSignal(false) const [allFiles, setAllFiles] = createSignal([]) const [isInitialized, setIsInitialized] = createSignal(false) let containerRef: HTMLDivElement | undefined let scrollContainerRef: HTMLDivElement | undefined async function fetchFiles(searchQuery: string) { setLoading(true) try { if (allFiles().length === 0) { const scannedPaths = await window.electronAPI.scanDirectory(props.workspaceFolder) const scannedFiles: FileItem[] = scannedPaths.map((path) => ({ path, isGitFile: false, })) setAllFiles(scannedFiles) } const filteredFiles = searchQuery.trim() ? allFiles().filter((f) => f.path.toLowerCase().includes(searchQuery.toLowerCase())) : allFiles() setFiles(filteredFiles) setSelectedIndex(0) setTimeout(() => { if (scrollContainerRef) { scrollContainerRef.scrollTop = 0 } }, 0) } catch (error) { console.error(`[UnifiedPicker] Failed to fetch files:`, error) setFiles([]) } finally { setLoading(false) } } let lastQuery = "" createEffect(() => { if (props.open && !isInitialized()) { setIsInitialized(true) fetchFiles(props.searchQuery) lastQuery = props.searchQuery return } if (props.open && props.searchQuery !== lastQuery) { lastQuery = props.searchQuery fetchFiles(props.searchQuery) } }) createEffect(() => { if (!props.open) return const query = props.searchQuery.toLowerCase() const filtered = query ? props.agents.filter( (agent) => agent.name.toLowerCase().includes(query) || (agent.description && agent.description.toLowerCase().includes(query)), ) : props.agents setFilteredAgents(filtered) }) const allItems = (): PickerItem[] => { const items: PickerItem[] = [] filteredAgents().forEach((agent) => items.push({ type: "agent", agent })) files().forEach((file) => items.push({ type: "file", file })) return items } function scrollToSelected() { setTimeout(() => { const selectedElement = containerRef?.querySelector('[data-picker-selected="true"]') if (selectedElement) { selectedElement.scrollIntoView({ block: "nearest", behavior: "smooth" }) } }, 0) } function handleSelect(item: PickerItem) { props.onSelect(item) } function handleKeyDown(e: KeyboardEvent) { if (!props.open) return const items = allItems() if (e.key === "ArrowDown") { e.preventDefault() setSelectedIndex((prev) => Math.min(prev + 1, items.length - 1)) scrollToSelected() } else if (e.key === "ArrowUp") { e.preventDefault() setSelectedIndex((prev) => Math.max(prev - 1, 0)) scrollToSelected() } else if (e.key === "Enter") { e.preventDefault() const selected = items[selectedIndex()] if (selected) { handleSelect(selected) } } else if (e.key === "Escape") { e.preventDefault() props.onClose() } } createEffect(() => { if (props.open) { document.addEventListener("keydown", handleKeyDown) onCleanup(() => { document.removeEventListener("keydown", handleKeyDown) }) } }) const agentCount = () => filteredAgents().length const fileCount = () => files().length return ( ) } export default UnifiedPicker