# Detail Panel 7-Issue Fix Implementation Plan > **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Fix 7 issues in ZCLAW desktop detail panel — P0 broken functionality, P1 data disconnects, P2 UX gaps. **Architecture:** Path B — System Bridge. Fix bugs directly; bridge disconnected backend systems to frontend without adding new SaaS endpoints, stores, or middleware. **Tech Stack:** Rust (Tauri commands, VikingStorage), TypeScript (React, Zustand), Tailwind CSS. **Spec:** `docs/superpowers/specs/2026-04-11-detail-panel-7-fixes-design.md` --- ## File Map | Action | File | Responsibility | |--------|------|----------------| | Modify | `desktop/src-tauri/src/memory_commands.rs:159-164` | Fix empty-query memory search (Issue 3) | | Modify | `desktop/src/lib/autonomy-manager.ts:258-276` | Fix hand_trigger null mapping (Issue 5) | | Modify | `desktop/src/lib/autonomy-manager.ts:105-157` | Add handAutoTrigger to default configs (Issue 5) | | Modify | `desktop/src/lib/saas-session.ts:162-172` | Add timestamp to connection mode (Issue 1) | | Modify | `desktop/src/store/saasStore.ts:690-696` | Write timestamp on degrade (Issue 1) | | Modify | `desktop/src/store/saasStore.ts:750-798` | Validate token before accepting persisted mode (Issue 1) | | Modify | `desktop/src-tauri/src/intelligence/reflection.rs:393-463` | Lower pattern thresholds (Issue 4) | | Modify | `desktop/src-tauri/src/intelligence_hooks.rs:116-121` | Fix pop → peek (Issue 4) | | Modify | `desktop/src-tauri/src/kernel_commands/agent.rs:169-184` | Extend agent_get with UserProfile (Issue 2) | | Modify | `desktop/src/components/RightPanel.tsx:374-386` | Contextual header for butler tab (Issue 7) | | Modify | `desktop/src/components/RightPanel.tsx:523-557` | Dual-source "How I See You" rendering (Issue 2) | | Modify | `desktop/src/components/IdentityChangeProposal.tsx:269-304` | Expandable HistoryItem (Issue 6) | | Modify | `desktop/src/components/ButlerPanel/index.tsx` | Enhanced empty state + analyze button (Issue 7) | | Modify | `desktop/src/components/ReflectionLog.tsx` | Enhanced reflection visibility (Issue 4) | --- ## Chunk 1: Batch 1 — P0 Fixes (Issues 3, 5, 1) ### Task 1: Fix memory_search empty query (Issue 3) **Files:** - Modify: `desktop/src-tauri/src/memory_commands.rs:159-164` - [ ] **Step 1: Write the fix** In `memory_commands.rs`, after line 159 (`let query = ...`) and before line 161 (`let find_options = ...`), add empty-query fallback logic: ```rust // Build search query let query = options.query.unwrap_or_default(); // When query is empty, use min_similarity=0.0 to trigger table scan // (FTS5 requires non-empty query; without this, empty query returns 0 results) let min_similarity = if query.trim().is_empty() { Some(0.0) } else { options.min_importance.map(|i| (i as f32) / 10.0) }; let find_options = zclaw_growth::FindOptions { scope, limit: options.limit.or(Some(50)), min_similarity, }; ``` This replaces lines 159-165 with the above logic. - [ ] **Step 2: Verify Rust compilation** Run: `cd g:/ZClaw_openfang && cargo check -p zclaw-kernel 2>&1 | tail -5` Expected: `Finished` without errors - [ ] **Step 3: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src-tauri/src/memory_commands.rs git commit -m "fix(memory): memory_search 空查询时默认 min_similarity=0.0 触发表扫描 根因: FTS5 空查询返回 0 条,而 memory_stats 因设 min_similarity=Some(0.0) 走表扫描才正确计数。统一空查询行为。 Closes #3" ``` --- ### Task 2: Fix hand_trigger null mapping (Issue 5) **Files:** - Modify: `desktop/src/lib/autonomy-manager.ts:258-276` (actionMap) - Modify: `desktop/src/lib/autonomy-manager.ts:105-157` (default configs) - [ ] **Step 1: Add handAutoTrigger to allowedActions type** Find the `allowedActions` type definition (search for `interface` or type that defines `memoryAutoSave`, `identityAutoUpdate`, etc.). Add: ```typescript handAutoTrigger: boolean; ``` to the allowedActions shape. It's defined inline in `AutonomyConfig` interface — find `autoReflection: boolean;` and add `handAutoTrigger: boolean;` after it. - [ ] **Step 2: Update actionMap at line 268** Change line 268 from: ```typescript hand_trigger: null, ``` to: ```typescript hand_trigger: 'handAutoTrigger', ``` - [ ] **Step 3: Add handAutoTrigger to all three default configs** In `DEFAULT_AUTONOMY_CONFIGS` (lines 105-157), add `handAutoTrigger` to each level: - `supervised` (line 114): add `handAutoTrigger: false,` after `autoReflection: false,` - `assisted` (line 131): add `handAutoTrigger: false,` after `autoReflection: true,` - `autonomous` (line 148): add `handAutoTrigger: true,` after `autoReflection: true,` - [ ] **Step 4: Verify TypeScript compilation** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: No errors related to `handAutoTrigger` - [ ] **Step 5: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src/lib/autonomy-manager.ts git commit -m "fix(autonomy): hand_trigger 从 null 映射改为 handAutoTrigger 字段 根因: autonomy-manager.ts:268 将 hand_trigger 硬编码为 null, 导致任何自主权级别都无法自动触发 Hand。 新增 handAutoTrigger 字段,autonomous 级别默认 true。 Closes #5" ``` --- ### Task 3: Add handAutoTrigger toggle to AutonomyConfig UI **Files:** - Modify: `desktop/src/components/AutonomyConfig.tsx` - [ ] **Step 1: Find the toggle section** Search `AutonomyConfig.tsx` for existing toggle patterns (e.g., `memoryAutoSave`, `autoReflection`). Find where toggles are rendered. - [ ] **Step 2: Add handAutoTrigger toggle** Add a toggle row following the existing pattern, with label: - Chinese: "自动触发 Hand 能力" - Description: "允许自动执行已启用的自主能力包" - Map to `allowedActions.handAutoTrigger` - [ ] **Step 3: Verify TypeScript compilation** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: No errors - [ ] **Step 4: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src/components/AutonomyConfig.tsx git commit -m "feat(ui): 自主配置增加 Hand 自动触发开关" ``` --- ### Task 4: Fix chat routing after restart (Issue 1) **Files:** - Modify: `desktop/src/lib/saas-session.ts:162-172` - Modify: `desktop/src/store/saasStore.ts:690-696, 750-798` - [ ] **Step 1: Add timestamp to saveConnectionMode** In `saas-session.ts`, change `saveConnectionMode` (line 162-164) to: ```typescript export function saveConnectionMode(mode: string): void { const data = JSON.stringify({ mode, timestamp: Date.now() }); localStorage.setItem(SAASMODE_KEY, data); } ``` And change `loadConnectionMode` (line 170-172) to: ```typescript export function loadConnectionMode(): string | null { const raw = localStorage.getItem(SAASMODE_KEY); if (!raw) return null; try { const parsed = JSON.parse(raw); if (typeof parsed === 'string') return parsed; // legacy format return parsed.mode ?? null; } catch { return raw; // legacy format (plain string) } } export function loadConnectionModeTimestamp(): number | null { const raw = localStorage.getItem(SAASMODE_KEY); if (!raw) return null; try { const parsed = JSON.parse(raw); return parsed.timestamp ?? null; } catch { return null; } } ``` - [ ] **Step 2: Update restoreSession to re-validate degraded mode** In `saasStore.ts` `restoreSession()` (line 750), after `const restored = await loadSaaSSession();` and before accepting the persisted connection mode, add staleness validation. The key change: after the existing token refresh logic (around line 798), before the function decides the final connection mode, check: ```typescript import { loadConnectionModeTimestamp } from '../lib/saas-session'; // After token validation logic completes... // If account was successfully retrieved via refresh, force 'saas' mode if (account) { set({ isAuthenticated: true, account, token: newToken, connectionMode: 'saas', saasReachable: true, }); saveConnectionMode('saas'); return; } ``` This is the critical fix: if token refresh succeeds, always restore to 'saas' mode regardless of what was persisted. The existing code already does this implicitly if `account` is set, but the issue is that the persisted `'tauri'` mode in localStorage overrides this elsewhere. Verify the full restoreSession flow sets `connectionMode` correctly after account retrieval. - [ ] **Step 3: Verify the degrade path writes timestamp correctly** Verify `saveConnectionMode('tauri')` call at line 696 now writes timestamp via the updated function. - [ ] **Step 4: Verify TypeScript compilation** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: No errors - [ ] **Step 5: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src/lib/saas-session.ts desktop/src/store/saasStore.ts git commit -m "fix(auth): 修复重启后无法对话 — restoreSession 优先验证 SaaS token 根因: 心跳降级将 'tauri' 持久化到 localStorage,重启后盲信该值。 修复: token refresh 成功时强制恢复 'saas' 模式;connectionMode 携带时间戳。 Closes #1" ``` --- ### Task 5: Batch 1 verification - [ ] **Step 1: Full TypeScript check** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: 0 errors - [ ] **Step 2: Full Rust check** Run: `cd g:/ZClaw_openfang && cargo check 2>&1 | tail -5` Expected: `Finished` without errors - [ ] **Step 3: Frontend tests** Run: `cd g:/ZClaw_openfang/desktop && npx vitest run 2>&1 | tail -10` Expected: All tests pass - [ ] **Step 4: Push** ```bash cd g:/ZClaw_openfang && git push ``` --- ## Chunk 2: Batch 2 — P1 Fixes (Issues 4, 2) ### Task 6: Lower reflection pattern thresholds (Issue 4 — part 1) **Files:** - Modify: `desktop/src-tauri/src/intelligence/reflection.rs:393-463` - [ ] **Step 1: Lower thresholds in analyze_patterns()** Change 5 threshold values in `analyze_patterns()`: | Pattern | Old | New | Line | |---------|-----|-----|------| | task accumulation | `>= 5` | `>= 3` | 393 | | preference accumulation | `>= 5` | `>= 3` | 411 | | lessons learned | `>= 5` | `>= 3` | 429 | | high-access memories | `>= 3` | `>= 2` | 450 | | low-importance memories | `> 20` | `> 15` | 463 | Also update observation text for low-importance: - Line 465: `"有 {} 条低重要性记忆,建议清理"` → `"有 {} 条低重要性记忆,可考虑清理"` - [ ] **Step 2: Verify Rust compilation** Run: `cd g:/ZClaw_openfang && cargo check 2>&1 | tail -5` Expected: `Finished` without errors - [ ] **Step 3: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src-tauri/src/intelligence/reflection.rs git commit -m "fix(reflection): 降低模式检测阈值 5→3/20→15 以产生更多有意义反思" ``` --- ### Task 7: Fix reflection state restore race (Issue 4 — part 2) **Files:** - Modify: `desktop/src-tauri/src/intelligence/reflection.rs:705-722` (pop → peek) - Modify: `desktop/src-tauri/src/intelligence_hooks.rs:116-121` (consume pattern) - [ ] **Step 1: Add peek functions alongside pop** In `reflection.rs`, after `pop_restored_result()` (line 722), add peek variants: ```rust /// Peek restored state from cache (non-destructive read) pub fn peek_restored_state(agent_id: &str) -> Option { let cache = get_state_cache(); cache.read().ok()?.get(agent_id).cloned() } /// Peek restored result from cache (non-destructive read) pub fn peek_restored_result(agent_id: &str) -> Option { let cache = get_result_cache(); cache.read().ok()?.get(agent_id).cloned() } ``` Note: `ReflectionState` and `ReflectionResult` must derive `Clone`. Verify they do; if not, add `#[derive(Clone)]`. - [ ] **Step 2: Update intelligence_hooks to use peek + cleanup-on-next** In `intelligence_hooks.rs`, change lines 116-121 from: ```rust if let Some(restored_state) = crate::intelligence::reflection::pop_restored_state(agent_id) { engine.apply_restored_state(restored_state); } if let Some(restored_result) = crate::intelligence::reflection::pop_restored_result(agent_id) { engine.apply_restored_result(restored_result); } ``` to: ```rust if let Some(restored_state) = crate::intelligence::reflection::peek_restored_state(agent_id) { engine.apply_restored_state(restored_state); // Pop after successful apply to prevent re-processing crate::intelligence::reflection::pop_restored_state(agent_id); } if let Some(restored_result) = crate::intelligence::reflection::peek_restored_result(agent_id) { engine.apply_restored_result(restored_result); crate::intelligence::reflection::pop_restored_result(agent_id); } ``` This ensures `getHistory` can find the data in VikingStorage before it's consumed. The pop happens after apply, not before read. - [ ] **Step 3: Verify Rust compilation** Run: `cd g:/ZClaw_openfang && cargo check 2>&1 | tail -5` Expected: `Finished` without errors - [ ] **Step 4: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src-tauri/src/intelligence/reflection.rs desktop/src-tauri/src/intelligence_hooks.rs git commit -m "fix(reflection): 修复 state restore 竞态 — peek+pop 替代直接 pop 根因: pop_restored_state 在 getHistory 读取前删除数据。 修复: 先 peek 非破坏性读取,apply 后再 pop,确保数据可被多次读取。" ``` --- ### Task 8: Enhance reflection visibility UI (Issue 4 — part 3) **Files:** - Modify: `desktop/src/components/ReflectionLog.tsx` - [ ] **Step 1: Find the history item rendering** Search for the component that renders reflection history entries. Find where each entry displays its content. - [ ] **Step 2: Add pattern/improvement/proposal summary to each entry** For each reflection history entry, add summary badges: - Pattern count badge: `发现 {n} 个模式` - Improvement count badge: `{n} 条建议` - Identity proposal count badge: `{n} 项身份变更` Also add timeline text: "第 {conversations} 次对话后触发" - [ ] **Step 3: Add expandable detail section** When a history entry is clicked/expanded, show: - Pattern observations (observation text, sentiment, frequency) - Improvement suggestions (area, suggestion, priority) - Identity proposals count - [ ] **Step 4: Verify TypeScript compilation** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: No errors - [ ] **Step 5: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src/components/ReflectionLog.tsx git commit -m "feat(ui): 反思历史增加模式/建议/提案摘要 + 可展开详情" ``` --- ### Task 9: Extend agent_get with UserProfile (Issue 2 — part 1) **Files:** - Modify: `desktop/src-tauri/src/kernel_commands/agent.rs:169-184` - [ ] **Step 1: Check AgentInfo type** Search for `AgentInfo` struct definition (likely in `crates/zclaw-kernel/src/kernel/agents.rs` or `crates/zclaw-types/src/agent.rs`). Understand its current fields. - [ ] **Step 2: Add optional user_profile field to AgentInfo** Add to `AgentInfo`: ```rust pub user_profile: Option, ``` If `UserProfile` doesn't implement `Serialize`/`Clone`, add the derives. - [ ] **Step 3: Populate user_profile in agent_get command** In `agent.rs` `agent_get()`, after getting the agent info, fetch UserProfile: ```rust pub async fn agent_get( state: State<'_, KernelState>, agent_id: String, ) -> Result, String> { let agent_id = validate_agent_id(&agent_id)?; let kernel_lock = state.lock().await; let kernel = kernel_lock.as_ref() .ok_or_else(|| "Kernel not initialized".to_string())?; let id: AgentId = agent_id.parse() .map_err(|_| "Invalid agent ID format".to_string())?; let mut info = kernel.get_agent(&id); // Extend with UserProfile if available if let Some(ref mut agent_info) = info { if let Ok(storage) = crate::viking_commands::get_storage().await { let profile_store = zclaw_memory::UserProfileStore::new(storage); agent_info.user_profile = profile_store.get(&agent_id).await.ok(); } } Ok(info) } ``` Note: Adjust the exact API based on how `UserProfileStore` is constructed and its `get` method signature. Verify in `crates/zclaw-memory/src/user_profile_store.rs`. - [ ] **Step 4: Verify Rust compilation** Run: `cd g:/ZClaw_openfang && cargo check 2>&1 | tail -5` Expected: `Finished` without errors - [ ] **Step 5: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src-tauri/src/kernel_commands/agent.rs git commit -m "feat(kernel): agent_get 返回值扩展 UserProfile 字段 复用已有 UserProfileStore,不新增 Tauri 命令。 前端可从 agent 数据直接读取用户画像。" ``` --- ### Task 10: RightPanel dual-source "How I See You" (Issue 2 — part 2) **Files:** - Modify: `desktop/src/components/RightPanel.tsx:523-557` - Modify: `desktop/src/store/chat/streamStore.ts` (add profile refresh trigger) - [ ] **Step 1: Add userProfile state to RightPanel** Near the top of the `RightPanel` component function, add: ```typescript const [userProfile, setUserProfile] = useState(null); ``` - [ ] **Step 2: Fetch UserProfile on mount and agent change** Add a `useEffect` that fetches agent data (which now includes user_profile) when `currentAgent?.id` changes: ```typescript useEffect(() => { if (!currentAgent?.id) return; // Fetch full agent data including UserProfile intelligenceClient.agents.getAgent(currentAgent.id) .then(data => setUserProfile(data?.user_profile ?? null)) .catch(() => setUserProfile(null)); }, [currentAgent?.id]); ``` Adjust the API call based on how the frontend fetches agent data. Check `desktop/src/lib/kernel-agent.ts` or `gateway-api.ts` for the `getAgent` method. - [ ] **Step 3: Render dual-source "How I See You"** In the "我眼中的你" section (lines 523-557), after the existing static Clone fields, add dynamic UserProfile fields: ```tsx {/* Dynamic: UserProfile data (from conversation learning) */} {userProfile && (
对话中了解到的
{userProfile.industry && (
行业: {userProfile.industry}
)} {userProfile.role && (
角色: {userProfile.role}
)} {userProfile.communication_style && (
沟通偏好: {userProfile.communication_style}
)} {userProfile.recent_topics?.length > 0 && (
近期话题: {userProfile.recent_topics.slice(0, 5).join(', ')}
)}
)} ``` - [ ] **Step 4: Add refresh trigger after stream completion** In `streamStore.ts`, find the flow completion callback (~line 446 where `getMemoryExtractor().extractFromConversation()` is called). After it, add a trigger to refresh the agent's UserProfile. Use a custom event or direct re-fetch: ```typescript // After memory extraction completes, notify RightPanel to refresh UserProfile window.dispatchEvent(new CustomEvent('zclaw:agent-profile-updated', { detail: { agentId } })); ``` In RightPanel, listen for this event: ```typescript useEffect(() => { const handler = (e: CustomEvent) => { if (e.detail.agentId === currentAgent?.id) { // Re-fetch agent data including updated UserProfile intelligenceClient.agents.getAgent(currentAgent.id) .then(data => setUserProfile(data?.user_profile ?? null)) .catch(() => {}); } }; window.addEventListener('zclaw:agent-profile-updated', handler as EventListener); return () => window.removeEventListener('zclaw:agent-profile-updated', handler as EventListener); }, [currentAgent?.id]); ``` - [ ] **Step 5: Verify TypeScript compilation** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: No errors - [ ] **Step 6: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src/components/RightPanel.tsx desktop/src/store/chat/streamStore.ts git commit -m "feat(ui): '我眼中的你' 双源渲染 — 静态Clone + 动态UserProfile 桥接 identity 系统 → 前端面板,对话结束后自动刷新画像。 Closes #2" ``` --- ### Task 11: Batch 2 verification - [ ] **Step 1: Full TypeScript check** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: 0 errors - [ ] **Step 2: Full Rust check** Run: `cd g:/ZClaw_openfang && cargo check 2>&1 | tail -5` Expected: `Finished` without errors - [ ] **Step 3: Frontend tests** Run: `cd g:/ZClaw_openfang/desktop && npx vitest run 2>&1 | tail -10` Expected: All tests pass - [ ] **Step 4: Push** ```bash cd g:/ZClaw_openfang && git push ``` --- ## Chunk 3: Batch 3 — P2 Fixes (Issues 6, 7) ### Task 12: Add expandable diff to HistoryItem (Issue 6) **Files:** - Modify: `desktop/src/components/IdentityChangeProposal.tsx:269-304` - [ ] **Step 1: Add expand state to HistoryItem** Modify `HistoryItem` component to add expandable state and file change display: ```tsx function HistoryItem({ snapshot, onRestore, isRestoring, }: { snapshot: IdentitySnapshot; onRestore: () => void; isRestoring: boolean; }) { const [expanded, setExpanded] = useState(false); const timeAgo = getTimeAgo(snapshot.timestamp); // Determine which files changed const fileNames: string[] = []; if (snapshot.files) { if (snapshot.files.soul) fileNames.push('soul'); if (snapshot.files.instructions) fileNames.push('instructions'); if (snapshot.files.user_profile) fileNames.push('user_profile'); } const fileColorMap: Record = { soul: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300', instructions: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300', user_profile: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300', }; return (
setExpanded(!expanded)} >
{timeAgo}
{fileNames.length > 0 && ( {fileNames.length} 个文件 )}

{snapshot.reason || '自动快照'}

{fileNames.length > 0 && (
{fileNames.map(name => ( {name} ))}
)}
{expanded && snapshot.files && (
{snapshot.files.soul && (
Soul
                {typeof snapshot.files.soul === 'string'
                  ? snapshot.files.soul.slice(0, 500)
                  : JSON.stringify(snapshot.files.soul, null, 2).slice(0, 500)}
              
)} {snapshot.files.instructions && (
Instructions
                {typeof snapshot.files.instructions === 'string'
                  ? snapshot.files.instructions.slice(0, 500)
                  : JSON.stringify(snapshot.files.instructions, null, 2).slice(0, 500)}
              
)}
)}
); } ``` Note: Adjust `snapshot.files` field names based on actual `IdentitySnapshot` type definition. Check `desktop/src/lib/intelligence-client/types.ts` for the exact shape. - [ ] **Step 2: Verify TypeScript compilation** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: No errors - [ ] **Step 3: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src/components/IdentityChangeProposal.tsx git commit -m "feat(ui): 演化历史条目增加可展开差异视图 + 文件变更标签 点击展开显示 soul/instructions 变更内容,不再截断原因文本。 Closes #6" ``` --- ### Task 13: Butler contextual header (Issue 7 — part 1) **Files:** - Modify: `desktop/src/components/RightPanel.tsx:374-386` - [ ] **Step 1: Add conditional rendering for stats bar** Wrap the existing message stats bar (lines 374-386) with a condition: ```tsx {/* 消息统计 — 但ler tab 时显示管家专用摘要 */} {activeTab === 'butler' ? (
管家模式
{connected ? : } {runtimeSummary}
) : (
{messageCount} 条消息 | {userMsgCount} 用户 / {assistantMsgCount} 助手
{connected ? : } {runtimeSummary}
)} ``` - [ ] **Step 2: Verify TypeScript compilation** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: No errors - [ ] **Step 3: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src/components/RightPanel.tsx git commit -m "fix(ui): 管家 Tab 统计栏显示管家专属摘要,不再显示聊天统计" ``` --- ### Task 14: Butler empty state enhancement (Issue 7 — part 2) **Files:** - Modify: `desktop/src/components/ButlerPanel/index.tsx` - [ ] **Step 1: Add empty state and analyze button** Modify `ButlerPanel` to show enhanced empty state when all data is empty: ```tsx import { useButlerInsights } from '../../hooks/useButlerInsights'; import { useConversationStore } from '../../store/chat/conversationStore'; import { InsightsSection } from './InsightsSection'; import { ProposalsSection } from './ProposalsSection'; import { MemorySection } from './MemorySection'; interface ButlerPanelProps { agentId: string | undefined; } export function ButlerPanel({ agentId }: ButlerPanelProps) { const { painPoints, proposals, loading, error, refresh } = useButlerInsights(agentId); const messageCount = useConversationStore((s) => s.messages.length); const [analyzing, setAnalyzing] = useState(false); const hasData = (painPoints?.length ?? 0) > 0 || (proposals?.length ?? 0) > 0; const canAnalyze = messageCount >= 2; const handleAnalyze = async () => { if (!canAnalyze || analyzing) return; setAnalyzing(true); try { await refresh(); } finally { setAnalyzing(false); } }; if (!agentId) { return (

请先选择一个 Agent

); } return (
{error && (
{error}
)} {loading && (
)} {!loading && !hasData && (

管家正在了解您,多轮对话后会自动发现您的需求

)} {(hasData || loading) && ( <>

我最近在关注

我提出的方案

)}

我记得关于您

); } ``` Note: Add `import { useState } from 'react';` if not already imported. - [ ] **Step 2: Verify TypeScript compilation** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: No errors - [ ] **Step 3: Commit** ```bash cd g:/ZClaw_openfang git add desktop/src/components/ButlerPanel/index.tsx git commit -m "feat(ui): 管家 Tab 空状态增加引导文案 + 立即分析按钮 - 无数据时显示友好引导文案 - 分析按钮要求至少 2 条对话 - 分析中显示加载状态 Closes #7" ``` --- ### Task 15: Batch 3 verification + final push - [ ] **Step 1: Full TypeScript check** Run: `cd g:/ZClaw_openfang/desktop && npx tsc --noEmit 2>&1 | tail -10` Expected: 0 errors - [ ] **Step 2: Full Rust check** Run: `cd g:/ZClaw_openfang && cargo check 2>&1 | tail -5` Expected: `Finished` without errors - [ ] **Step 3: Frontend tests** Run: `cd g:/ZClaw_openfang/desktop && npx vitest run 2>&1 | tail -10` Expected: All tests pass - [ ] **Step 4: Push all batches** ```bash cd g:/ZClaw_openfang && git push ``` - [ ] **Step 5: Update documentation per CLAUDE.md §8.3** Update `docs/TRUTH.md` if Tauri command count changed (only if agent_get signature was modified). Update `wiki/log.md` with change record. Append entry: ``` ### [2026-04-11] 详情面板 7 问题修复 - P0: 聊天路由竞态/记忆查询缺陷/hand_trigger硬编码 - P1: Agent画像桥接/反思持久化+阈值 - P2: 演化差异视图/管家Tab上下文 ``` - [ ] **Step 6: Commit and push docs** ```bash cd g:/ZClaw_openfang git add docs/TRUTH.md wiki/log.md git commit -m "docs: 详情面板7问题修复记录" git push ``` --- ## Summary | Batch | Tasks | Issues | Files Modified | |-------|-------|--------|----------------| | 1 | 1-5 | 3, 5, 1 | memory_commands.rs, autonomy-manager.ts, AutonomyConfig.tsx, saas-session.ts, saasStore.ts | | 2 | 6-11 | 4, 2 | reflection.rs, intelligence_hooks.rs, ReflectionLog.tsx, agent.rs, RightPanel.tsx, streamStore.ts | | 3 | 12-15 | 6, 7 | IdentityChangeProposal.tsx, RightPanel.tsx, ButlerPanel/index.tsx | **Total: 15 tasks, 3 batches, ~14 files modified**