fix(desktop): component cleanup + dead code removal + DeerFlow ai-elements
- ChatArea: DeerFlow ai-elements annotations for accessibility - Conversation: remove unused Context, simplify message rendering - Delete dead modules: audit-logger.ts, gateway-reconnect.ts - Replace console.log with structured logger across components - Add idb dependency for IndexedDB persistence - Fix kernel-skills type safety improvements
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
import { useState, useEffect, useRef, useCallback, useMemo, type MutableRefObject, type RefObject, type CSSProperties } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { List, type ListImperativeAPI } from 'react-window';
|
||||
import { useChatStore, Message } from '../store/chatStore';
|
||||
import { useChatStore, type Message } from '../store/chatStore';
|
||||
import { useConversationStore } from '../store/chat/conversationStore';
|
||||
import { useArtifactStore } from '../store/chat/artifactStore';
|
||||
import { useConnectionStore } from '../store/connectionStore';
|
||||
import { useAgentStore } from '../store/agentStore';
|
||||
import { useConfigStore } from '../store/configStore';
|
||||
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
|
||||
import { Paperclip, SquarePen, ArrowUp, MessageSquare, Download, X, FileText, Image as ImageIcon } from 'lucide-react';
|
||||
import { Button, EmptyState, MessageListSkeleton, LoadingDots } from './ui';
|
||||
import { ResizableChatLayout } from './ai/ResizableChatLayout';
|
||||
@@ -45,11 +47,14 @@ const VIRTUALIZATION_THRESHOLD = 100;
|
||||
|
||||
export function ChatArea() {
|
||||
const {
|
||||
messages, currentAgent, isStreaming, isLoading, currentModel,
|
||||
sendMessage: sendToGateway, setCurrentModel, initStreamListener,
|
||||
messages, isStreaming, isLoading,
|
||||
sendMessage: sendToGateway, initStreamListener,
|
||||
newConversation, chatMode, setChatMode, suggestions,
|
||||
totalInputTokens, totalOutputTokens,
|
||||
} = useChatStore();
|
||||
const currentAgent = useConversationStore((s) => s.currentAgent);
|
||||
const currentModel = useConversationStore((s) => s.currentModel);
|
||||
const setCurrentModel = useConversationStore((s) => s.setCurrentModel);
|
||||
const {
|
||||
artifacts, selectedArtifactId, artifactPanelOpen,
|
||||
selectArtifact, setArtifactPanelOpen,
|
||||
@@ -152,6 +157,29 @@ export function ChatArea() {
|
||||
return unsub;
|
||||
}, []);
|
||||
|
||||
// Listen for hand-execution-complete Tauri events
|
||||
useEffect(() => {
|
||||
let unlisten: UnlistenFn | undefined;
|
||||
listen<{ approvalId: string; handId: string; success: boolean; error?: string | null }>(
|
||||
'hand-execution-complete',
|
||||
(event) => {
|
||||
const { handId, success, error } = event.payload;
|
||||
useChatStore.getState().addMessage({
|
||||
id: crypto.randomUUID(),
|
||||
role: 'hand',
|
||||
content: success
|
||||
? `Hand ${handId} 执行完成`
|
||||
: `Hand ${handId} 执行失败: ${error || '未知错误'}`,
|
||||
timestamp: new Date(),
|
||||
handName: handId,
|
||||
handStatus: success ? 'completed' : 'failed',
|
||||
handResult: event.payload,
|
||||
});
|
||||
},
|
||||
).then((fn) => { unlisten = fn; });
|
||||
return () => { unlisten?.(); };
|
||||
}, []);
|
||||
|
||||
// Auto-scroll to bottom on new messages
|
||||
useEffect(() => {
|
||||
if (scrollRef.current && !useVirtualization) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useAgentStore } from '../store/agentStore';
|
||||
import { useConnectionStore } from '../store/connectionStore';
|
||||
import { useConfigStore } from '../store/configStore';
|
||||
import { toChatAgent, useChatStore } from '../store/chatStore';
|
||||
import { useConversationStore } from '../store/chat/conversationStore';
|
||||
import { Bot, Plus, X, Globe, Cat, Search, BarChart2, Sparkles } from 'lucide-react';
|
||||
import { AgentOnboardingWizard } from './AgentOnboardingWizard';
|
||||
import type { Clone } from '../store/agentStore';
|
||||
@@ -13,7 +14,8 @@ export function CloneManager() {
|
||||
const deleteClone = useAgentStore((s) => s.deleteClone);
|
||||
const connectionState = useConnectionStore((s) => s.connectionState);
|
||||
const quickConfig = useConfigStore((s) => s.quickConfig);
|
||||
const { agents, currentAgent, setCurrentAgent } = useChatStore();
|
||||
const { agents, currentAgent } = useConversationStore();
|
||||
const setCurrentAgent = useChatStore((s) => s.setCurrentAgent);
|
||||
const [showWizard, setShowWizard] = useState(false);
|
||||
|
||||
const connected = connectionState === 'connected';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { useConversationStore } from '../store/chat/conversationStore';
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { MessageSquare, Trash2, SquarePen, Download, Check, X } from 'lucide-react';
|
||||
import { EmptyConversations } from './ui';
|
||||
@@ -171,15 +172,14 @@ function ConversationItem({
|
||||
}
|
||||
|
||||
export function ConversationList() {
|
||||
const {
|
||||
conversations,
|
||||
currentConversationId,
|
||||
switchConversation,
|
||||
deleteConversation,
|
||||
} = useChatStore();
|
||||
const conversations = useConversationStore((s) => s.conversations);
|
||||
const currentConversationId = useConversationStore((s) => s.currentConversationId);
|
||||
const { switchConversation, deleteConversation } = useChatStore();
|
||||
// suppress unused-var lint — these facade actions are needed
|
||||
void switchConversation; void deleteConversation;
|
||||
|
||||
const handleRename = (id: string, newTitle: string) => {
|
||||
useChatStore.setState((state) => ({
|
||||
useConversationStore.setState((state) => ({
|
||||
conversations: state.conversations.map((c) =>
|
||||
c.id === id ? { ...c, title: newTitle, updatedAt: new Date() } : c
|
||||
),
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
type IdentityChangeProposal as Proposal,
|
||||
type IdentitySnapshot,
|
||||
} from '../lib/intelligence-client';
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { useConversationStore } from '../store/chat/conversationStore';
|
||||
import { Button, Badge } from './ui';
|
||||
|
||||
// === Error Parsing Utility ===
|
||||
@@ -306,7 +306,7 @@ function HistoryItem({
|
||||
// === Main Component ===
|
||||
|
||||
export function IdentityChangeProposalPanel() {
|
||||
const { currentAgent } = useChatStore();
|
||||
const currentAgent = useConversationStore((s) => s.currentAgent);
|
||||
const [proposals, setProposals] = useState<Proposal[]>([]);
|
||||
const [snapshots, setSnapshots] = useState<IdentitySnapshot[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
type GraphEdge,
|
||||
type MemoryType,
|
||||
} from '../store/memoryGraphStore';
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { useConversationStore } from '../store/chat/conversationStore';
|
||||
import { cardHover, defaultTransition } from '../lib/animations';
|
||||
|
||||
// Mark as intentionally unused for future use
|
||||
@@ -157,7 +157,7 @@ export function MemoryGraph({ className = '' }: MemoryGraphProps) {
|
||||
const [showFilters, setShowFilters] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
|
||||
const { currentAgent } = useChatStore();
|
||||
const currentAgent = useConversationStore((s) => s.currentAgent);
|
||||
const agentId = currentAgent?.id || 'zclaw-main';
|
||||
|
||||
const {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
type MemoryType,
|
||||
type MemoryStats,
|
||||
} from '../lib/intelligence-client';
|
||||
import { useChatStore } from '../store/chatStore';
|
||||
import { useConversationStore } from '../store/chat/conversationStore';
|
||||
|
||||
const TYPE_LABELS: Record<MemoryType, { label: string; emoji: string; color: string }> = {
|
||||
fact: { label: '事实', emoji: '📋', color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300' },
|
||||
@@ -23,7 +23,7 @@ const TYPE_LABELS: Record<MemoryType, { label: string; emoji: string; color: str
|
||||
};
|
||||
|
||||
export function MemoryPanel() {
|
||||
const { currentAgent } = useChatStore();
|
||||
const currentAgent = useConversationStore((s) => s.currentAgent);
|
||||
const agentId = currentAgent?.id || 'zclaw-main';
|
||||
|
||||
const [memories, setMemories] = useState<MemoryEntry[]>([]);
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useConnectionStore } from '../store/connectionStore';
|
||||
import { useAgentStore, type PluginStatus } from '../store/agentStore';
|
||||
import { useConfigStore } from '../store/configStore';
|
||||
import { toChatAgent, useChatStore, type CodeBlock } from '../store/chatStore';
|
||||
import { useConversationStore } from '../store/chat/conversationStore';
|
||||
import {
|
||||
Wifi, WifiOff, Bot, BarChart3, Plug, RefreshCw,
|
||||
MessageSquare, Cpu, FileText, User, Activity, Brain,
|
||||
@@ -100,7 +101,9 @@ export function RightPanel() {
|
||||
const workspaceInfo = useConfigStore((s) => s.workspaceInfo);
|
||||
const quickConfig = useConfigStore((s) => s.quickConfig);
|
||||
|
||||
const { messages, currentModel, currentAgent, setCurrentAgent } = useChatStore();
|
||||
const { messages, setCurrentAgent } = useChatStore();
|
||||
const currentModel = useConversationStore((s) => s.currentModel);
|
||||
const currentAgent = useConversationStore((s) => s.currentAgent);
|
||||
const [activeTab, setActiveTab] = useState<'status' | 'files' | 'agent' | 'memory' | 'reflection' | 'autonomy' | 'evolution'>('status');
|
||||
const [memoryViewMode, setMemoryViewMode] = useState<'list' | 'graph'>('list');
|
||||
const [isEditingAgent, setIsEditingAgent] = useState(false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useConnectionStore } from '../../store/connectionStore';
|
||||
import { useConfigStore } from '../../store/configStore';
|
||||
import { useChatStore } from '../../store/chatStore';
|
||||
import { useConversationStore } from '../../store/chat/conversationStore';
|
||||
import { getStoredGatewayToken, setStoredGatewayToken } from '../../lib/gateway-client';
|
||||
import { silentErrorHandler } from '../../lib/error-utils';
|
||||
|
||||
@@ -13,7 +13,7 @@ export function General() {
|
||||
const disconnect = useConnectionStore((s) => s.disconnect);
|
||||
const quickConfig = useConfigStore((s) => s.quickConfig);
|
||||
const saveQuickConfig = useConfigStore((s) => s.saveQuickConfig);
|
||||
const currentModel = useChatStore((s) => s.currentModel);
|
||||
const currentModel = useConversationStore((s) => s.currentModel);
|
||||
const [theme, setTheme] = useState<'light' | 'dark'>(quickConfig.theme || 'light');
|
||||
const [autoStart, setAutoStart] = useState(quickConfig.autoStart ?? false);
|
||||
const [showToolCalls, setShowToolCalls] = useState(quickConfig.showToolCalls ?? false);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
import { getStoredGatewayToken, getStoredGatewayUrl } from '../../lib/gateway-client';
|
||||
import { useConnectionStore } from '../../store/connectionStore';
|
||||
import { useConfigStore } from '../../store/configStore';
|
||||
import { useChatStore } from '../../store/chatStore';
|
||||
import { useConversationStore } from '../../store/chat/conversationStore';
|
||||
import { silentErrorHandler } from '../../lib/error-utils';
|
||||
import { secureStorage } from '../../lib/secure-storage';
|
||||
import { Plus, Pencil, Trash2, Star, Eye, EyeOff, AlertCircle, X, Zap, Check } from 'lucide-react';
|
||||
@@ -166,7 +166,8 @@ export function ModelsAPI() {
|
||||
const disconnect = useConnectionStore((s) => s.disconnect);
|
||||
const quickConfig = useConfigStore((s) => s.quickConfig);
|
||||
const loadModels = useConfigStore((s) => s.loadModels);
|
||||
const { currentModel, setCurrentModel } = useChatStore();
|
||||
const currentModel = useConversationStore((s) => s.currentModel);
|
||||
const setCurrentModel = useConversationStore((s) => s.setCurrentModel);
|
||||
const [gatewayUrl, setGatewayUrl] = useState(getStoredGatewayUrl());
|
||||
const [gatewayToken, setGatewayToken] = useState(quickConfig.gatewayToken || getStoredGatewayToken());
|
||||
|
||||
|
||||
@@ -1,41 +1,4 @@
|
||||
import { useRef, useEffect, useState, createContext, useContext, useMemo, type ReactNode } from 'react';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ConversationContext — shared state for child ai-elements components
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
interface ConversationContextValue {
|
||||
isStreaming: boolean;
|
||||
setIsStreaming: (v: boolean) => void;
|
||||
messages: unknown[];
|
||||
setMessages: (msgs: unknown[]) => void;
|
||||
}
|
||||
|
||||
const ConversationContext = createContext<ConversationContextValue | null>(null);
|
||||
|
||||
export function useConversationContext() {
|
||||
const ctx = useContext(ConversationContext);
|
||||
if (!ctx) {
|
||||
throw new Error('useConversationContext must be used within ConversationProvider');
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
export function ConversationProvider({ children }: { children: ReactNode }) {
|
||||
const [isStreaming, setIsStreaming] = useState(false);
|
||||
const [messages, setMessages] = useState<unknown[]>([]);
|
||||
|
||||
const value = useMemo(
|
||||
() => ({ isStreaming, setIsStreaming, messages, setMessages }),
|
||||
[isStreaming, messages],
|
||||
);
|
||||
|
||||
return (
|
||||
<ConversationContext.Provider value={value}>
|
||||
{children}
|
||||
</ConversationContext.Provider>
|
||||
);
|
||||
}
|
||||
import { useRef, useEffect, type ReactNode } from 'react';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Conversation container with auto-stick-to-bottom scroll behavior
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export { Conversation, ConversationProvider, useConversationContext } from './Conversation';
|
||||
export { Conversation } from './Conversation';
|
||||
export { ReasoningBlock } from './ReasoningBlock';
|
||||
export { StreamingText } from './StreamingText';
|
||||
export { ChatMode, type ChatModeType, type ChatModeConfig, CHAT_MODES } from './ChatMode';
|
||||
|
||||
Reference in New Issue
Block a user