cc工作前备份

This commit is contained in:
iven
2026-03-12 00:23:42 +08:00
parent f75a2b798b
commit ef849c62ab
98 changed files with 12110 additions and 568 deletions

View File

@@ -0,0 +1,217 @@
import { create } from 'zustand';
import { GatewayClient, ConnectionState, getGatewayClient } from '../lib/gateway-client';
interface GatewayLog {
timestamp: number;
level: string;
message: string;
}
interface Clone {
id: string;
name: string;
role?: string;
nickname?: string;
scenarios?: string[];
model?: string;
createdAt: string;
}
interface UsageStats {
totalSessions: number;
totalMessages: number;
totalTokens: number;
byModel: Record<string, { messages: number; inputTokens: number; outputTokens: number }>;
}
interface ChannelInfo {
id: string;
type: string;
label: string;
status: 'active' | 'inactive' | 'error';
accounts?: number;
error?: string;
}
interface ScheduledTask {
id: string;
name: string;
schedule: string;
status: 'active' | 'paused' | 'completed' | 'error';
lastRun?: string;
nextRun?: string;
description?: string;
}
interface GatewayStore {
// Connection state
connectionState: ConnectionState;
gatewayVersion: string | null;
error: string | null;
logs: GatewayLog[];
// Data
clones: Clone[];
usageStats: UsageStats | null;
pluginStatus: any[];
channels: ChannelInfo[];
scheduledTasks: ScheduledTask[];
// Client reference
client: GatewayClient;
// Actions
connect: (url?: string, token?: string) => Promise<void>;
disconnect: () => void;
sendMessage: (message: string, sessionKey?: string) => Promise<{ runId: string }>;
loadClones: () => Promise<void>;
createClone: (opts: { name: string; role?: string; scenarios?: string[] }) => Promise<void>;
deleteClone: (id: string) => Promise<void>;
loadUsageStats: () => Promise<void>;
loadPluginStatus: () => Promise<void>;
loadChannels: () => Promise<void>;
loadScheduledTasks: () => Promise<void>;
clearLogs: () => void;
}
export const useGatewayStore = create<GatewayStore>((set, get) => {
const client = getGatewayClient();
// Wire up state change callback
client.onStateChange = (state) => {
set({ connectionState: state });
};
client.onLog = (level, message) => {
set((s) => ({
logs: [...s.logs.slice(-99), { timestamp: Date.now(), level, message }],
}));
};
return {
connectionState: 'disconnected',
gatewayVersion: null,
error: null,
logs: [],
clones: [],
usageStats: null,
pluginStatus: [],
channels: [],
scheduledTasks: [],
client,
connect: async (url?: string, token?: string) => {
try {
set({ error: null });
const c = url ? getGatewayClient({ url, token }) : get().client;
await c.connect();
// Fetch initial data after connection
try {
const health = await c.health();
set({ gatewayVersion: health?.version });
} catch { /* health may not return version */ }
} catch (err: any) {
set({ error: err.message });
throw err;
}
},
disconnect: () => {
get().client.disconnect();
},
sendMessage: async (message: string, sessionKey?: string) => {
const c = get().client;
return c.chat(message, { sessionKey });
},
loadClones: async () => {
try {
const result = await get().client.listClones();
set({ clones: result?.clones || [] });
} catch { /* ignore if method not available */ }
},
createClone: async (opts) => {
try {
await get().client.createClone(opts);
await get().loadClones();
} catch (err: any) {
set({ error: err.message });
}
},
deleteClone: async (id: string) => {
try {
await get().client.deleteClone(id);
await get().loadClones();
} catch (err: any) {
set({ error: err.message });
}
},
loadUsageStats: async () => {
try {
const stats = await get().client.getUsageStats();
set({ usageStats: stats });
} catch { /* ignore */ }
},
loadPluginStatus: async () => {
try {
const result = await get().client.getPluginStatus();
set({ pluginStatus: result?.plugins || [] });
} catch { /* ignore */ }
},
loadChannels: async () => {
const channels: { id: string; type: string; label: string; status: 'active' | 'inactive' | 'error'; accounts?: number; error?: string }[] = [];
try {
// Try listing channels from Gateway
const result = await get().client.listChannels();
if (result?.channels) {
set({ channels: result.channels });
return;
}
} catch { /* channels.list may not be available */ }
// Fallback: probe known channels individually
try {
const feishu = await get().client.getFeishuStatus();
channels.push({
id: 'feishu',
type: 'feishu',
label: '飞书 (Feishu)',
status: feishu?.configured ? 'active' : 'inactive',
accounts: feishu?.accounts || 0,
});
} catch {
channels.push({ id: 'feishu', type: 'feishu', label: '飞书 (Feishu)', status: 'inactive' });
}
// QQ channel (check if qqbot plugin is loaded)
const plugins = get().pluginStatus;
const qqPlugin = plugins.find((p: any) => (p.name || p.id || '').toLowerCase().includes('qqbot'));
if (qqPlugin) {
channels.push({
id: 'qqbot',
type: 'qqbot',
label: 'QQ 机器人',
status: qqPlugin.status === 'active' ? 'active' : 'inactive',
});
}
set({ channels });
},
loadScheduledTasks: async () => {
try {
const result = await get().client.listScheduledTasks();
set({ scheduledTasks: result?.tasks || [] });
} catch { /* ignore if heartbeat.tasks not available */ }
},
clearLogs: () => set({ logs: [] }),
};
});