import { writable, derived } from "svelte/store"; import type { ConnectionStatus, PermissionRequest } from "$lib/types/messages"; export interface TerminalLine { id: string; type: "user" | "assistant" | "system" | "tool" | "error"; content: string; timestamp: Date; toolName?: string; } function createClaudeStore() { const connectionStatus = writable("disconnected"); const sessionId = writable(null); const currentWorkingDirectory = writable(""); const terminalLines = writable([]); const pendingPermission = writable(null); const isProcessing = writable(false); const grantedTools = writable>(new Set()); const pendingRetryMessage = writable(null); let lineIdCounter = 0; function generateLineId(): string { return `line-${Date.now()}-${lineIdCounter++}`; } return { connectionStatus: { subscribe: connectionStatus.subscribe }, sessionId: { subscribe: sessionId.subscribe }, currentWorkingDirectory: { subscribe: currentWorkingDirectory.subscribe }, terminalLines: { subscribe: terminalLines.subscribe }, pendingPermission: { subscribe: pendingPermission.subscribe }, isProcessing: { subscribe: isProcessing.subscribe }, grantedTools: { subscribe: grantedTools.subscribe }, pendingRetryMessage: { subscribe: pendingRetryMessage.subscribe }, setConnectionStatus: (status: ConnectionStatus) => connectionStatus.set(status), setSessionId: (id: string | null) => sessionId.set(id), setWorkingDirectory: (dir: string) => currentWorkingDirectory.set(dir), setProcessing: (processing: boolean) => isProcessing.set(processing), addLine: (type: TerminalLine["type"], content: string, toolName?: string) => { const line: TerminalLine = { id: generateLineId(), type, content, timestamp: new Date(), toolName, }; terminalLines.update((lines) => [...lines, line]); return line.id; }, updateLine: (id: string, content: string) => { terminalLines.update((lines) => lines.map((line) => (line.id === id ? { ...line, content } : line)) ); }, appendToLine: (id: string, additionalContent: string) => { terminalLines.update((lines) => lines.map((line) => line.id === id ? { ...line, content: line.content + additionalContent } : line ) ); }, clearTerminal: () => terminalLines.set([]), getConversationHistory: (): string => { let lines: TerminalLine[] = []; terminalLines.subscribe((l) => (lines = l))(); // Filter to just user and assistant messages, skip system/tool noise const relevantLines = lines.filter( (line) => line.type === "user" || line.type === "assistant" ); if (relevantLines.length === 0) return ""; return relevantLines .map((line) => { const role = line.type === "user" ? "User" : "Assistant"; return `${role}: ${line.content}`; }) .join("\n\n"); }, requestPermission: (request: PermissionRequest) => pendingPermission.set(request), clearPermission: () => pendingPermission.set(null), grantTool: (toolName: string) => { grantedTools.update((tools) => { const newTools = new Set(tools); newTools.add(toolName); return newTools; }); }, getGrantedTools: (): string[] => { let tools: string[] = []; grantedTools.subscribe((t) => (tools = Array.from(t)))(); return tools; }, setPendingRetryMessage: (message: string | null) => pendingRetryMessage.set(message), reset: () => { connectionStatus.set("disconnected"); sessionId.set(null); currentWorkingDirectory.set(""); terminalLines.set([]); pendingPermission.set(null); isProcessing.set(false); grantedTools.set(new Set()); pendingRetryMessage.set(null); }, }; } export const claudeStore = createClaudeStore(); export const hasPermissionPending = derived( claudeStore.pendingPermission, ($permission) => $permission !== null );