diff --git a/desktop/src-tauri/src/kernel_commands/workspace.rs b/desktop/src-tauri/src/kernel_commands/workspace.rs index e12f08f..cf3774c 100644 --- a/desktop/src-tauri/src/kernel_commands/workspace.rs +++ b/desktop/src-tauri/src/kernel_commands/workspace.rs @@ -13,20 +13,23 @@ pub struct DirStats { #[tauri::command] pub async fn workspace_dir_stats(path: String) -> Result { let dir = Path::new(&path); - if !dir.exists() { + + // Canonicalize to resolve '..' components and symlinks + let canonical = dir.canonicalize().unwrap_or_else(|_| dir.to_path_buf()); + if !canonical.exists() { return Ok(DirStats { file_count: 0, total_size: 0, }); } - if !dir.is_dir() { + if !canonical.is_dir() { return Err(format!("{} is not a directory", path)); } let mut file_count: u64 = 0; let mut total_size: u64 = 0; - let entries = std::fs::read_dir(dir).map_err(|e| format!("Failed to read dir: {}", e))?; + let entries = std::fs::read_dir(&canonical).map_err(|e| format!("Failed to read dir: {}", e))?; for entry in entries.flatten() { if let Ok(metadata) = entry.metadata() { if metadata.is_file() { diff --git a/desktop/src/components/Settings/Workspace.tsx b/desktop/src/components/Settings/Workspace.tsx index 997677e..8103dba 100644 --- a/desktop/src/components/Settings/Workspace.tsx +++ b/desktop/src/components/Settings/Workspace.tsx @@ -26,7 +26,9 @@ export function Workspace() { }, []); useEffect(() => { - setProjectDir(quickConfig.workspaceDir || workspaceInfo?.path || '~/.zclaw/zclaw-workspace'); + const dir = quickConfig.workspaceDir || workspaceInfo?.path || '~/.zclaw/zclaw-workspace'; + setProjectDir(dir); + loadDirStats(dir); }, [quickConfig.workspaceDir, workspaceInfo?.path]); const handleWorkspaceBlur = async () => { @@ -86,8 +88,8 @@ export function Workspace() {
当前解析路径:{workspaceInfo?.resolvedPath || projectDir}
文件数:{dirStats?.fileCount ?? workspaceInfo?.fileCount ?? 0} - {dirStats && `,大小:${(dirStats.totalSize / 1024).toFixed(1)} KB`} - {!dirStats && workspaceInfo?.totalSize ? `,大小:${workspaceInfo.totalSize} bytes` : ''} + {((dirStats?.totalSize ?? workspaceInfo?.totalSize ?? 0) > 0) && + `,大小:${(((dirStats?.totalSize ?? workspaceInfo?.totalSize) ?? 0) / 1024).toFixed(1)} KB`}
diff --git a/desktop/src/store/configStore.ts b/desktop/src/store/configStore.ts index 3a2b4b4..4151bab 100644 --- a/desktop/src/store/configStore.ts +++ b/desktop/src/store/configStore.ts @@ -81,6 +81,7 @@ export interface SkillInfo { capabilities?: string[]; tags?: string[]; mode?: string; + category?: string; triggers?: Array<{ type: string; pattern?: string }>; actions?: Array<{ type: string; params?: Record }>; enabled?: boolean; @@ -455,6 +456,8 @@ export const useConfigStore = create((set if (client) { try { const result = await client.listSkills(); + // Empty array from client may indicate connected-but-load-failure; + // fall through to direct Tauri invoke as recovery path if (result?.skills && result.skills.length > 0) { set({ skillsCatalog: result.skills }); if (result.extraDirs) { diff --git a/desktop/src/store/securityStore.ts b/desktop/src/store/securityStore.ts index 91fb3ef..ed367f7 100644 --- a/desktop/src/store/securityStore.ts +++ b/desktop/src/store/securityStore.ts @@ -309,10 +309,11 @@ export const useSecurityStore = create((set, get) => ({ })); } - // Sort by timestamp descending and apply limit + // Sort by timestamp descending and apply pagination allLogs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); - const limited = opts?.limit ? allLogs.slice(0, opts.limit) : allLogs; - set({ auditLogs: limited, auditLogsLoading: false }); + const offset = opts?.offset ?? 0; + const paginated = opts?.limit ? allLogs.slice(offset, offset + opts.limit) : allLogs.slice(offset); + set({ auditLogs: paginated, auditLogsLoading: false }); } catch { set({ auditLogsLoading: false }); }