fix(ui): 9项端到端真实审计 — 修复记忆/技能/审计/工作区/MCP数据流断裂
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
基于 Tauri MCP 实机排查发现并修复:
1. VikingPanel: viking_ls('/') 返回0 → 改为 viking_ls('') 返回100条记忆
2. 技能列表: loadSkillsCatalog 静默失败 → 添加直接 invoke('skill_list') 回退
3. 审计日志: 面板读Gateway API无数据 → 回退读localStorage双源数据
4. 工作区: 浏览按钮无事件 → 接入prompt选择 + workspace_dir_stats 命令
5. MCP: 空列表无引导 → 添加配置文件路径提示
6. 新增 workspace_dir_stats Tauri 命令 (Rust)
排查确认正常的功能: 安全存储(OS Keyring✅), 心跳引擎(运行中✅),
定时任务(管道连通), Kernel(已初始化✅), SaaS relay模式
This commit is contained in:
@@ -450,21 +450,50 @@ export const useConfigStore = create<ConfigStateSlice & ConfigActionsSlice>((set
|
||||
|
||||
loadSkillsCatalog: async () => {
|
||||
const client = get().client;
|
||||
if (!client) return;
|
||||
|
||||
try {
|
||||
const result = await client.listSkills();
|
||||
set({ skillsCatalog: result?.skills || [] });
|
||||
if (result?.extraDirs) {
|
||||
set((state) => ({
|
||||
quickConfig: {
|
||||
...state.quickConfig,
|
||||
skillsExtraDirs: result.extraDirs,
|
||||
},
|
||||
}));
|
||||
// Path A: via injected client (KernelClient or GatewayClient)
|
||||
if (client) {
|
||||
try {
|
||||
const result = await client.listSkills();
|
||||
if (result?.skills && result.skills.length > 0) {
|
||||
set({ skillsCatalog: result.skills });
|
||||
if (result.extraDirs) {
|
||||
set((state) => ({
|
||||
quickConfig: {
|
||||
...state.quickConfig,
|
||||
skillsExtraDirs: result.extraDirs,
|
||||
},
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[configStore] listSkills via client failed, trying direct invoke:', err);
|
||||
}
|
||||
} catch {
|
||||
// Ignore if skills list not available
|
||||
}
|
||||
|
||||
// Path B: direct Tauri invoke fallback (works even without client injection)
|
||||
try {
|
||||
const skills = await invoke('skill_list');
|
||||
if (Array.isArray(skills) && skills.length > 0) {
|
||||
set({ skillsCatalog: skills.map((s: Record<string, unknown>) => ({
|
||||
id: s.id as string,
|
||||
name: s.name as string,
|
||||
description: (s.description as string) || '',
|
||||
version: (s.version as string) || '',
|
||||
capabilities: (s.capabilities as string[]) || [],
|
||||
tags: (s.tags as string[]) || [],
|
||||
mode: (s.mode as string) || '',
|
||||
triggers: ((s.triggers as string[]) || []).map((t: string) => ({ type: 'keyword' as const, pattern: t })),
|
||||
actions: ((s.capabilities as string[]) || []).map((cap: string) => ({ type: cap, params: undefined })),
|
||||
enabled: (s.enabled as boolean) ?? true,
|
||||
category: s.category as string,
|
||||
source: ((s.source as string) || 'builtin') as 'builtin' | 'extra',
|
||||
path: s.path as string | undefined,
|
||||
})) });
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[configStore] skill_list direct invoke also failed:', err);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -257,16 +257,64 @@ export const useSecurityStore = create<SecurityStore>((set, get) => ({
|
||||
},
|
||||
|
||||
loadAuditLogs: async (opts?: { limit?: number; offset?: number }) => {
|
||||
const client = get().client;
|
||||
if (!client) return;
|
||||
|
||||
set({ auditLogsLoading: true });
|
||||
|
||||
// Path A: try client (Gateway mode)
|
||||
const client = get().client;
|
||||
if (client) {
|
||||
try {
|
||||
const result = await client.getAuditLogs(opts);
|
||||
if (result?.logs && result.logs.length > 0) {
|
||||
set({ auditLogs: result.logs as AuditLogEntry[], auditLogsLoading: false });
|
||||
return;
|
||||
}
|
||||
} catch { /* fallback to local */ }
|
||||
}
|
||||
|
||||
// Path B: read from localStorage (Tauri/Kernel mode)
|
||||
try {
|
||||
const result = await client.getAuditLogs(opts);
|
||||
set({ auditLogs: (result?.logs || []) as AuditLogEntry[], auditLogsLoading: false });
|
||||
const allLogs: AuditLogEntry[] = [];
|
||||
|
||||
// Source 1: security-audit.ts events (zclaw_security_audit_log)
|
||||
const securityLog = localStorage.getItem('zclaw_security_audit_log');
|
||||
if (securityLog) {
|
||||
const events = JSON.parse(securityLog) as Array<{
|
||||
id: string; timestamp: string; eventType: string; severity: string;
|
||||
description: string; details?: Record<string, unknown>;
|
||||
}>;
|
||||
events.forEach(e => allLogs.push({
|
||||
id: e.id,
|
||||
timestamp: e.timestamp,
|
||||
action: e.eventType,
|
||||
actor: 'system',
|
||||
result: e.severity === 'critical' || e.severity === 'high' ? 'failure' : 'success',
|
||||
details: { description: e.description, ...e.details },
|
||||
}));
|
||||
}
|
||||
|
||||
// Source 2: autonomy audit log (zclaw-autonomy-audit-log)
|
||||
const autonomyLog = localStorage.getItem('zclaw-autonomy-audit-log');
|
||||
if (autonomyLog) {
|
||||
const events = JSON.parse(autonomyLog) as Array<{
|
||||
id: string; timestamp: string; action: string;
|
||||
decision?: Record<string, unknown>; outcome?: string;
|
||||
}>;
|
||||
events.forEach(e => allLogs.push({
|
||||
id: e.id,
|
||||
timestamp: e.timestamp,
|
||||
action: `autonomy.${e.action}`,
|
||||
actor: 'system',
|
||||
result: e.outcome === 'success' ? 'success' : 'failure',
|
||||
details: e.decision || {},
|
||||
}));
|
||||
}
|
||||
|
||||
// Sort by timestamp descending and apply limit
|
||||
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 });
|
||||
} catch {
|
||||
set({ auditLogsLoading: false });
|
||||
/* ignore if audit API not available */
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user