import { FileIcon, Icon, IconButton, Tooltip } from "@/ui" import * as KobalteTabs from "@kobalte/core/tabs" import FileTree from "@/components/file-tree" import EditorPane from "@/components/editor-pane" import { For, Match, onCleanup, onMount, Show, Switch } from "solid-js" import { SelectDialog } from "@/components/select-dialog" import { useSync, useSDK, useLocal } from "@/context" import type { LocalFile, TextSelection } from "@/context/local" import SessionList from "@/components/session-list" import SessionTimeline from "@/components/session-timeline" import PromptForm, { type PromptContentPart, type PromptSubmitValue } from "@/components/prompt-form" import { createStore } from "solid-js/store" import { getDirectory, getFilename } from "@/utils" import { Select } from "@/components/select" import { Tabs } from "@/ui/tabs" import { Code } from "@/components/code" export default function Page() { const local = useLocal() const sync = useSync() const sdk = useSDK() const [store, setStore] = createStore({ clickTimer: undefined as number | undefined, modelSelectOpen: false, fileSelectOpen: false, }) let inputRef: HTMLTextAreaElement | undefined = undefined const MOD = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) ? "Meta" : "Control" onMount(() => { document.addEventListener("keydown", handleKeyDown) }) onCleanup(() => { document.removeEventListener("keydown", handleKeyDown) }) const handleKeyDown = (event: KeyboardEvent) => { if (event.getModifierState(MOD) && event.shiftKey && event.key.toLowerCase() === "p") { event.preventDefault() // TODO: command palette return } if (event.getModifierState(MOD) && event.key.toLowerCase() === "p") { event.preventDefault() setStore("fileSelectOpen", true) return } const focused = document.activeElement === inputRef if (focused) { if (event.key === "Escape") { inputRef?.blur() } return } if (local.file.active()) { const active = local.file.active()! if (event.key === "Enter" && active.selection) { local.context.add({ type: "file", path: active.path, selection: { ...active.selection }, }) return } if (event.getModifierState(MOD)) { if (event.key.toLowerCase() === "a") { return } if (event.key.toLowerCase() === "c") { return } } } if (event.key.length === 1 && event.key !== "Unidentified") { inputRef?.focus() } } const resetClickTimer = () => { if (!store.clickTimer) return clearTimeout(store.clickTimer) setStore("clickTimer", undefined) } const startClickTimer = () => { const newClickTimer = setTimeout(() => { setStore("clickTimer", undefined) }, 300) setStore("clickTimer", newClickTimer as unknown as number) } const handleFileClick = async (file: LocalFile) => { if (store.clickTimer) { resetClickTimer() local.file.update(file.path, { ...file, pinned: true }) } else { local.file.open(file.path) startClickTimer() } } const handlePromptSubmit = async (prompt: PromptSubmitValue) => { const existingSession = local.session.active() let session = existingSession if (!session) { const created = await sdk.session.create() session = created.data ?? undefined } if (!session) return local.session.setActive(session.id) interface SubmissionAttachment { path: string selection?: TextSelection label: string } const createAttachmentKey = (path: string, selection?: TextSelection) => { if (!selection) return path return `${path}:${selection.startLine}:${selection.startChar}:${selection.endLine}:${selection.endChar}` } const formatAttachmentLabel = (path: string, selection?: TextSelection) => { if (!selection) return getFilename(path) return `${getFilename(path)} (${selection.startLine}-${selection.endLine})` } const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) const attachments = new Map() const registerAttachment = (path: string, selection: TextSelection | undefined, label?: string) => { if (!path) return const key = createAttachmentKey(path, selection) if (attachments.has(key)) return attachments.set(key, { path, selection, label: label ?? formatAttachmentLabel(path, selection), }) } const promptAttachments = prompt.parts.filter( (part): part is Extract => part.kind === "attachment", ) for (const part of promptAttachments) { registerAttachment(part.path, part.selection, part.display) } const activeFile = local.context.active() if (activeFile) { registerAttachment( activeFile.path, activeFile.selection, activeFile.name ?? formatAttachmentLabel(activeFile.path, activeFile.selection), ) } for (const contextFile of local.context.all()) { registerAttachment( contextFile.path, contextFile.selection, formatAttachmentLabel(contextFile.path, contextFile.selection), ) } const attachmentParts = Array.from(attachments.values()).map((attachment) => { const absolute = toAbsolutePath(attachment.path) const query = attachment.selection ? `?start=${attachment.selection.startLine}&end=${attachment.selection.endLine}` : "" return { type: "file" as const, mime: "text/plain", url: `file://${absolute}${query}`, filename: getFilename(attachment.path), source: { type: "file" as const, text: { value: `@${attachment.label}`, start: 0, end: 0, }, path: absolute, }, } }) await sdk.session.prompt({ path: { id: session.id }, body: { agent: local.agent.current()!.name, model: { modelID: local.model.current()!.id, providerID: local.model.current()!.provider.id, }, parts: [ { type: "text", text: prompt.text, }, ...attachmentParts, ], }, }) } return (
{(activeSession) => }
} >
    {(path) => (
  • )}
m.role === "user") ?? []} label={(m) => sync.data.part[m.id].find((p) => p.type === "text")!.text} class="bg-transparent! max-w-48 pl-0! text-text-muted!" />
setStore("fileSelectOpen", true)} > {(file) => ( props.onTabClick(props.file)} >
{getFilename(file.path)}
)}
{(file) => ( )}
setStore("modelSelectOpen", true)} onInputRefChange={(element: HTMLTextAreaElement | undefined) => { inputRef = element ?? undefined }} />
`${x.provider.id}:${x.id}`} items={local.model.list()} current={local.model.current()} render={(i) => (
{i.name} {i.id}
{new Intl.NumberFormat("en-US", { notation: "compact", compactDisplay: "short", }).format(i.limit.context)}
10}>$$$ 1}>$$ 0.1}>$
)} filter={["provider.name", "name", "id"]} groupBy={(x) => x.provider.name} onClose={() => setStore("modelSelectOpen", false)} onSelect={(x) => local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined)} />
x} render={(i) => (
{getFilename(i)} {getDirectory(i)}
)} onClose={() => setStore("fileSelectOpen", false)} onSelect={(x) => (x ? local.context.openFile(x) : undefined)} // onSelect={(x) => (x ? local.file.open(x, { pinned: true }) : undefined)} />
) }