refactor IPC (#341)
This commit is contained in:
committed by
GitHub
Unverified
parent
c03d92e9a2
commit
3d804a9f5e
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import type { Channel, ChannelType } from '../types/channel';
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
interface AddChannelParams {
|
||||
type: ChannelType;
|
||||
@@ -17,7 +18,7 @@ interface ChannelsState {
|
||||
error: string | null;
|
||||
|
||||
// Actions
|
||||
fetchChannels: () => Promise<void>;
|
||||
fetchChannels: (options?: { probe?: boolean; silent?: boolean }) => Promise<void>;
|
||||
addChannel: (params: AddChannelParams) => Promise<Channel>;
|
||||
deleteChannel: (channelId: string) => Promise<void>;
|
||||
connectChannel: (channelId: string) => Promise<void>;
|
||||
@@ -33,13 +34,17 @@ export const useChannelsStore = create<ChannelsState>((set, get) => ({
|
||||
loading: false,
|
||||
error: null,
|
||||
|
||||
fetchChannels: async () => {
|
||||
set({ loading: true, error: null });
|
||||
fetchChannels: async (options) => {
|
||||
const probe = options?.probe ?? false;
|
||||
const silent = options?.silent ?? false;
|
||||
if (!silent) {
|
||||
set({ loading: true, error: null });
|
||||
}
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'channels.status',
|
||||
{ probe: true }
|
||||
{ probe }
|
||||
) as {
|
||||
success: boolean;
|
||||
result?: {
|
||||
@@ -126,20 +131,20 @@ export const useChannelsStore = create<ChannelsState>((set, get) => ({
|
||||
});
|
||||
}
|
||||
|
||||
set({ channels, loading: false });
|
||||
set((state) => ({ channels, loading: silent ? state.loading : false }));
|
||||
} else {
|
||||
// Gateway not available - try to show channels from local config
|
||||
set({ channels: [], loading: false });
|
||||
set((state) => ({ channels: [], loading: silent ? state.loading : false }));
|
||||
}
|
||||
} catch {
|
||||
// Gateway not connected, show empty
|
||||
set({ channels: [], loading: false });
|
||||
set((state) => ({ channels: [], loading: silent ? state.loading : false }));
|
||||
}
|
||||
},
|
||||
|
||||
addChannel: async (params) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'channels.add',
|
||||
params
|
||||
@@ -184,13 +189,13 @@ export const useChannelsStore = create<ChannelsState>((set, get) => ({
|
||||
|
||||
try {
|
||||
// Delete the channel configuration from openclaw.json
|
||||
await window.electron.ipcRenderer.invoke('channel:deleteConfig', channelType);
|
||||
await invokeIpc('channel:deleteConfig', channelType);
|
||||
} catch (error) {
|
||||
console.error('Failed to delete channel config:', error);
|
||||
}
|
||||
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke(
|
||||
await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'channels.delete',
|
||||
{ channelId: channelType }
|
||||
@@ -211,7 +216,7 @@ export const useChannelsStore = create<ChannelsState>((set, get) => ({
|
||||
updateChannel(channelId, { status: 'connecting', error: undefined });
|
||||
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'channels.connect',
|
||||
{ channelId }
|
||||
@@ -231,7 +236,7 @@ export const useChannelsStore = create<ChannelsState>((set, get) => ({
|
||||
const { updateChannel } = get();
|
||||
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke(
|
||||
await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'channels.disconnect',
|
||||
{ channelId }
|
||||
@@ -244,7 +249,7 @@ export const useChannelsStore = create<ChannelsState>((set, get) => ({
|
||||
},
|
||||
|
||||
requestQrCode: async (channelType) => {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'channels.requestQr',
|
||||
{ type: channelType }
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Communicates with OpenClaw Gateway via gateway:rpc IPC.
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
// ── Types ────────────────────────────────────────────────────────
|
||||
|
||||
@@ -596,7 +597,7 @@ async function loadMissingPreviews(messages: RawMessage[]): Promise<boolean> {
|
||||
if (needPreview.length === 0) return false;
|
||||
|
||||
try {
|
||||
const thumbnails = await window.electron.ipcRenderer.invoke(
|
||||
const thumbnails = await invokeIpc(
|
||||
'media:getThumbnails',
|
||||
needPreview,
|
||||
) as Record<string, { preview: string | null; fileSize: number }>;
|
||||
@@ -928,7 +929,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
|
||||
loadSessions: async () => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'sessions.list',
|
||||
{}
|
||||
@@ -1001,7 +1002,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
void Promise.all(
|
||||
sessionsToLabel.map(async (session) => {
|
||||
try {
|
||||
const r = await window.electron.ipcRenderer.invoke(
|
||||
const r = await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'chat.history',
|
||||
{ sessionKey: session.key, limit: 1000 },
|
||||
@@ -1077,7 +1078,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
// The main process renames <suffix>.jsonl → <suffix>.deleted.jsonl so that
|
||||
// sessions.list and token-usage queries both skip it automatically.
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('session:delete', key) as {
|
||||
const result = await invokeIpc('session:delete', key) as {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
};
|
||||
@@ -1185,7 +1186,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
if (!quiet) set({ loading: true, error: null });
|
||||
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'chat.history',
|
||||
{ sessionKey: currentSessionKey, limit: 200 }
|
||||
@@ -1425,7 +1426,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
const CHAT_SEND_TIMEOUT_MS = 120_000;
|
||||
|
||||
if (hasMedia) {
|
||||
result = await window.electron.ipcRenderer.invoke(
|
||||
result = await invokeIpc(
|
||||
'chat:sendWithMedia',
|
||||
{
|
||||
sessionKey: currentSessionKey,
|
||||
@@ -1440,7 +1441,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
},
|
||||
) as { success: boolean; result?: { runId?: string }; error?: string };
|
||||
} else {
|
||||
result = await window.electron.ipcRenderer.invoke(
|
||||
result = await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'chat.send',
|
||||
{
|
||||
@@ -1477,7 +1478,7 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
||||
set({ streamingTools: [] });
|
||||
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke(
|
||||
await invokeIpc(
|
||||
'gateway:rpc',
|
||||
'chat.abort',
|
||||
{ sessionKey: currentSessionKey },
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import type { CronJob, CronJobCreateInput, CronJobUpdateInput } from '../types/cron';
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
interface CronState {
|
||||
jobs: CronJob[];
|
||||
@@ -29,7 +30,7 @@ export const useCronStore = create<CronState>((set) => ({
|
||||
set({ loading: true, error: null });
|
||||
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('cron:list') as CronJob[];
|
||||
const result = await invokeIpc<CronJob[]>('cron:list');
|
||||
set({ jobs: result, loading: false });
|
||||
} catch (error) {
|
||||
set({ error: String(error), loading: false });
|
||||
@@ -38,7 +39,7 @@ export const useCronStore = create<CronState>((set) => ({
|
||||
|
||||
createJob: async (input) => {
|
||||
try {
|
||||
const job = await window.electron.ipcRenderer.invoke('cron:create', input) as CronJob;
|
||||
const job = await invokeIpc<CronJob>('cron:create', input);
|
||||
set((state) => ({ jobs: [...state.jobs, job] }));
|
||||
return job;
|
||||
} catch (error) {
|
||||
@@ -49,7 +50,7 @@ export const useCronStore = create<CronState>((set) => ({
|
||||
|
||||
updateJob: async (id, input) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('cron:update', id, input);
|
||||
await invokeIpc('cron:update', id, input);
|
||||
set((state) => ({
|
||||
jobs: state.jobs.map((job) =>
|
||||
job.id === id ? { ...job, ...input, updatedAt: new Date().toISOString() } : job
|
||||
@@ -63,7 +64,7 @@ export const useCronStore = create<CronState>((set) => ({
|
||||
|
||||
deleteJob: async (id) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('cron:delete', id);
|
||||
await invokeIpc('cron:delete', id);
|
||||
set((state) => ({
|
||||
jobs: state.jobs.filter((job) => job.id !== id),
|
||||
}));
|
||||
@@ -75,7 +76,7 @@ export const useCronStore = create<CronState>((set) => ({
|
||||
|
||||
toggleJob: async (id, enabled) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('cron:toggle', id, enabled);
|
||||
await invokeIpc('cron:toggle', id, enabled);
|
||||
set((state) => ({
|
||||
jobs: state.jobs.map((job) =>
|
||||
job.id === id ? { ...job, enabled } : job
|
||||
@@ -89,11 +90,11 @@ export const useCronStore = create<CronState>((set) => ({
|
||||
|
||||
triggerJob: async (id) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('cron:trigger', id);
|
||||
const result = await invokeIpc<unknown>('cron:trigger', id);
|
||||
console.log('Cron trigger result:', result);
|
||||
// Refresh jobs after trigger to update lastRun/nextRun state
|
||||
try {
|
||||
const jobs = await window.electron.ipcRenderer.invoke('cron:list') as CronJob[];
|
||||
const jobs = await invokeIpc<CronJob[]>('cron:list');
|
||||
set({ jobs });
|
||||
} catch {
|
||||
// Ignore refresh error
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import type { GatewayStatus } from '../types/gateway';
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
let gatewayInitPromise: Promise<void> | null = null;
|
||||
|
||||
@@ -49,7 +50,7 @@ export const useGatewayStore = create<GatewayState>((set, get) => ({
|
||||
gatewayInitPromise = (async () => {
|
||||
try {
|
||||
// Get initial status first
|
||||
const status = await window.electron.ipcRenderer.invoke('gateway:status') as GatewayStatus;
|
||||
const status = await invokeIpc('gateway:status') as GatewayStatus;
|
||||
set({ status, isInitialized: true });
|
||||
|
||||
// Listen for status changes
|
||||
@@ -197,7 +198,7 @@ export const useGatewayStore = create<GatewayState>((set, get) => ({
|
||||
start: async () => {
|
||||
try {
|
||||
set({ status: { ...get().status, state: 'starting' }, lastError: null });
|
||||
const result = await window.electron.ipcRenderer.invoke('gateway:start') as { success: boolean; error?: string };
|
||||
const result = await invokeIpc('gateway:start') as { success: boolean; error?: string };
|
||||
|
||||
if (!result.success) {
|
||||
set({
|
||||
@@ -215,7 +216,7 @@ export const useGatewayStore = create<GatewayState>((set, get) => ({
|
||||
|
||||
stop: async () => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('gateway:stop');
|
||||
await invokeIpc('gateway:stop');
|
||||
set({ status: { ...get().status, state: 'stopped' }, lastError: null });
|
||||
} catch (error) {
|
||||
console.error('Failed to stop Gateway:', error);
|
||||
@@ -226,7 +227,7 @@ export const useGatewayStore = create<GatewayState>((set, get) => ({
|
||||
restart: async () => {
|
||||
try {
|
||||
set({ status: { ...get().status, state: 'starting' }, lastError: null });
|
||||
const result = await window.electron.ipcRenderer.invoke('gateway:restart') as { success: boolean; error?: string };
|
||||
const result = await invokeIpc('gateway:restart') as { success: boolean; error?: string };
|
||||
|
||||
if (!result.success) {
|
||||
set({
|
||||
@@ -244,7 +245,7 @@ export const useGatewayStore = create<GatewayState>((set, get) => ({
|
||||
|
||||
checkHealth: async () => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('gateway:health') as {
|
||||
const result = await invokeIpc('gateway:health') as {
|
||||
success: boolean;
|
||||
ok: boolean;
|
||||
error?: string;
|
||||
@@ -267,7 +268,7 @@ export const useGatewayStore = create<GatewayState>((set, get) => ({
|
||||
},
|
||||
|
||||
rpc: async <T>(method: string, params?: unknown, timeoutMs?: number): Promise<T> => {
|
||||
const result = await window.electron.ipcRenderer.invoke('gateway:rpc', method, params, timeoutMs) as {
|
||||
const result = await invokeIpc('gateway:rpc', method, params, timeoutMs) as {
|
||||
success: boolean;
|
||||
result?: T;
|
||||
error?: string;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import type { ProviderConfig, ProviderWithKeyInfo } from '@/lib/providers';
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
// Re-export types for consumers that imported from here
|
||||
export type { ProviderConfig, ProviderWithKeyInfo } from '@/lib/providers';
|
||||
@@ -45,8 +46,8 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
set({ loading: true, error: null });
|
||||
|
||||
try {
|
||||
const providers = await window.electron.ipcRenderer.invoke('provider:list') as ProviderWithKeyInfo[];
|
||||
const defaultId = await window.electron.ipcRenderer.invoke('provider:getDefault') as string | null;
|
||||
const providers = await invokeIpc<ProviderWithKeyInfo[]>('provider:list');
|
||||
const defaultId = await invokeIpc<string | null>('provider:getDefault');
|
||||
|
||||
set({
|
||||
providers,
|
||||
@@ -66,7 +67,7 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const result = await window.electron.ipcRenderer.invoke('provider:save', fullConfig, apiKey) as { success: boolean; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>('provider:save', fullConfig, apiKey);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to save provider');
|
||||
@@ -95,7 +96,7 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const result = await window.electron.ipcRenderer.invoke('provider:save', updatedConfig, apiKey) as { success: boolean; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>('provider:save', updatedConfig, apiKey);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to update provider');
|
||||
@@ -111,7 +112,7 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
|
||||
deleteProvider: async (providerId) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('provider:delete', providerId) as { success: boolean; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>('provider:delete', providerId);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to delete provider');
|
||||
@@ -127,7 +128,7 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
|
||||
setApiKey: async (providerId, apiKey) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('provider:setApiKey', providerId, apiKey) as { success: boolean; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>('provider:setApiKey', providerId, apiKey);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to set API key');
|
||||
@@ -143,12 +144,12 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
|
||||
updateProviderWithKey: async (providerId, updates, apiKey) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>(
|
||||
'provider:updateWithKey',
|
||||
providerId,
|
||||
updates,
|
||||
apiKey
|
||||
) as { success: boolean; error?: string };
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to update provider');
|
||||
@@ -163,7 +164,7 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
|
||||
deleteApiKey: async (providerId) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('provider:deleteApiKey', providerId) as { success: boolean; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>('provider:deleteApiKey', providerId);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to delete API key');
|
||||
@@ -179,7 +180,7 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
|
||||
setDefaultProvider: async (providerId) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('provider:setDefault', providerId) as { success: boolean; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>('provider:setDefault', providerId);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Failed to set default provider');
|
||||
@@ -194,12 +195,12 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
|
||||
validateApiKey: async (providerId, apiKey, options) => {
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc<{ valid: boolean; error?: string }>(
|
||||
'provider:validateKey',
|
||||
providerId,
|
||||
apiKey,
|
||||
options
|
||||
) as { valid: boolean; error?: string };
|
||||
);
|
||||
return result;
|
||||
} catch (error) {
|
||||
return { valid: false, error: String(error) };
|
||||
@@ -208,7 +209,7 @@ export const useProviderStore = create<ProviderState>((set, get) => ({
|
||||
|
||||
getApiKey: async (providerId) => {
|
||||
try {
|
||||
return await window.electron.ipcRenderer.invoke('provider:getApiKey', providerId) as string | null;
|
||||
return await invokeIpc<string | null>('provider:getApiKey', providerId);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import i18n from '@/i18n';
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
type Theme = 'light' | 'dark' | 'system';
|
||||
type UpdateChannel = 'stable' | 'beta' | 'dev';
|
||||
type GatewayTransportPreference = 'ws-first' | 'http-first' | 'ws-only' | 'http-only' | 'ipc-only';
|
||||
|
||||
interface SettingsState {
|
||||
// General
|
||||
@@ -25,6 +27,7 @@ interface SettingsState {
|
||||
proxyHttpsServer: string;
|
||||
proxyAllServer: string;
|
||||
proxyBypassRules: string;
|
||||
gatewayTransportPreference: GatewayTransportPreference;
|
||||
|
||||
// Update
|
||||
updateChannel: UpdateChannel;
|
||||
@@ -52,6 +55,7 @@ interface SettingsState {
|
||||
setProxyHttpsServer: (value: string) => void;
|
||||
setProxyAllServer: (value: string) => void;
|
||||
setProxyBypassRules: (value: string) => void;
|
||||
setGatewayTransportPreference: (value: GatewayTransportPreference) => void;
|
||||
setUpdateChannel: (channel: UpdateChannel) => void;
|
||||
setAutoCheckUpdate: (value: boolean) => void;
|
||||
setAutoDownloadUpdate: (value: boolean) => void;
|
||||
@@ -79,6 +83,7 @@ const defaultSettings = {
|
||||
proxyHttpsServer: '',
|
||||
proxyAllServer: '',
|
||||
proxyBypassRules: '<local>;localhost;127.0.0.1;::1',
|
||||
gatewayTransportPreference: 'ws-first' as GatewayTransportPreference,
|
||||
updateChannel: 'stable' as UpdateChannel,
|
||||
autoCheckUpdate: true,
|
||||
autoDownloadUpdate: false,
|
||||
@@ -94,7 +99,7 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
|
||||
init: async () => {
|
||||
try {
|
||||
const settings = await window.electron.ipcRenderer.invoke('settings:getAll') as Partial<typeof defaultSettings>;
|
||||
const settings = await invokeIpc<Partial<typeof defaultSettings>>('settings:getAll');
|
||||
set((state) => ({ ...state, ...settings }));
|
||||
if (settings.language) {
|
||||
i18n.changeLanguage(settings.language);
|
||||
@@ -106,17 +111,21 @@ export const useSettingsStore = create<SettingsState>()(
|
||||
},
|
||||
|
||||
setTheme: (theme) => set({ theme }),
|
||||
setLanguage: (language) => { i18n.changeLanguage(language); set({ language }); void window.electron.ipcRenderer.invoke('settings:set', 'language', language).catch(() => {}); },
|
||||
setLanguage: (language) => { i18n.changeLanguage(language); set({ language }); void invokeIpc('settings:set', 'language', language).catch(() => {}); },
|
||||
setStartMinimized: (startMinimized) => set({ startMinimized }),
|
||||
setLaunchAtStartup: (launchAtStartup) => set({ launchAtStartup }),
|
||||
setGatewayAutoStart: (gatewayAutoStart) => { set({ gatewayAutoStart }); void window.electron.ipcRenderer.invoke('settings:set', 'gatewayAutoStart', gatewayAutoStart).catch(() => {}); },
|
||||
setGatewayPort: (gatewayPort) => { set({ gatewayPort }); void window.electron.ipcRenderer.invoke('settings:set', 'gatewayPort', gatewayPort).catch(() => {}); },
|
||||
setGatewayAutoStart: (gatewayAutoStart) => { set({ gatewayAutoStart }); void invokeIpc('settings:set', 'gatewayAutoStart', gatewayAutoStart).catch(() => {}); },
|
||||
setGatewayPort: (gatewayPort) => { set({ gatewayPort }); void invokeIpc('settings:set', 'gatewayPort', gatewayPort).catch(() => {}); },
|
||||
setProxyEnabled: (proxyEnabled) => set({ proxyEnabled }),
|
||||
setProxyServer: (proxyServer) => set({ proxyServer }),
|
||||
setProxyHttpServer: (proxyHttpServer) => set({ proxyHttpServer }),
|
||||
setProxyHttpsServer: (proxyHttpsServer) => set({ proxyHttpsServer }),
|
||||
setProxyAllServer: (proxyAllServer) => set({ proxyAllServer }),
|
||||
setProxyBypassRules: (proxyBypassRules) => set({ proxyBypassRules }),
|
||||
setGatewayTransportPreference: (gatewayTransportPreference) => {
|
||||
set({ gatewayTransportPreference });
|
||||
void invokeIpc('settings:set', 'gatewayTransportPreference', gatewayTransportPreference).catch(() => {});
|
||||
},
|
||||
setUpdateChannel: (updateChannel) => set({ updateChannel }),
|
||||
setAutoCheckUpdate: (autoCheckUpdate) => set({ autoCheckUpdate }),
|
||||
setAutoDownloadUpdate: (autoDownloadUpdate) => set({ autoDownloadUpdate }),
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import type { Skill, MarketplaceSkill } from '../types/skill';
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
type GatewaySkillStatus = {
|
||||
skillKey: string;
|
||||
@@ -70,20 +71,20 @@ export const useSkillsStore = create<SkillsState>((set, get) => ({
|
||||
}
|
||||
try {
|
||||
// 1. Fetch from Gateway (running skills)
|
||||
const gatewayResult = await window.electron.ipcRenderer.invoke(
|
||||
const gatewayResult = await invokeIpc<GatewayRpcResponse<GatewaySkillsStatusResult>>(
|
||||
'gateway:rpc',
|
||||
'skills.status'
|
||||
) as GatewayRpcResponse<GatewaySkillsStatusResult>;
|
||||
);
|
||||
|
||||
// 2. Fetch from ClawHub (installed on disk)
|
||||
const clawhubResult = await window.electron.ipcRenderer.invoke(
|
||||
const clawhubResult = await invokeIpc<{ success: boolean; results?: ClawHubListResult[]; error?: string }>(
|
||||
'clawhub:list'
|
||||
) as { success: boolean; results?: ClawHubListResult[]; error?: string };
|
||||
);
|
||||
|
||||
// 3. Fetch configurations directly from Electron (since Gateway doesn't return them)
|
||||
const configResult = await window.electron.ipcRenderer.invoke(
|
||||
const configResult = await invokeIpc<Record<string, { apiKey?: string; env?: Record<string, string> }>>(
|
||||
'skill:getAllConfigs'
|
||||
) as Record<string, { apiKey?: string; env?: Record<string, string> }>;
|
||||
);
|
||||
|
||||
let combinedSkills: Skill[] = [];
|
||||
const currentSkills = get().skills;
|
||||
@@ -155,7 +156,7 @@ export const useSkillsStore = create<SkillsState>((set, get) => ({
|
||||
searchSkills: async (query: string) => {
|
||||
set({ searching: true, searchError: null });
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('clawhub:search', { query }) as { success: boolean; results?: MarketplaceSkill[]; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; results?: MarketplaceSkill[]; error?: string }>('clawhub:search', { query });
|
||||
if (result.success) {
|
||||
set({ searchResults: result.results || [] });
|
||||
} else {
|
||||
@@ -177,7 +178,7 @@ export const useSkillsStore = create<SkillsState>((set, get) => ({
|
||||
installSkill: async (slug: string, version?: string) => {
|
||||
set((state) => ({ installing: { ...state.installing, [slug]: true } }));
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('clawhub:install', { slug, version }) as { success: boolean; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>('clawhub:install', { slug, version });
|
||||
if (!result.success) {
|
||||
if (result.error?.includes('Timeout')) {
|
||||
throw new Error('installTimeoutError');
|
||||
@@ -204,7 +205,7 @@ export const useSkillsStore = create<SkillsState>((set, get) => ({
|
||||
uninstallSkill: async (slug: string) => {
|
||||
set((state) => ({ installing: { ...state.installing, [slug]: true } }));
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('clawhub:uninstall', { slug }) as { success: boolean; error?: string };
|
||||
const result = await invokeIpc<{ success: boolean; error?: string }>('clawhub:uninstall', { slug });
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || 'Uninstall failed');
|
||||
}
|
||||
@@ -226,11 +227,11 @@ export const useSkillsStore = create<SkillsState>((set, get) => ({
|
||||
const { updateSkill } = get();
|
||||
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc<GatewayRpcResponse<unknown>>(
|
||||
'gateway:rpc',
|
||||
'skills.update',
|
||||
{ skillKey: skillId, enabled: true }
|
||||
) as GatewayRpcResponse<unknown>;
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
updateSkill(skillId, { enabled: true });
|
||||
@@ -252,11 +253,11 @@ export const useSkillsStore = create<SkillsState>((set, get) => ({
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke(
|
||||
const result = await invokeIpc<GatewayRpcResponse<unknown>>(
|
||||
'gateway:rpc',
|
||||
'skills.update',
|
||||
{ skillKey: skillId, enabled: false }
|
||||
) as GatewayRpcResponse<unknown>;
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
updateSkill(skillId, { enabled: false });
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import { useSettingsStore } from './settings';
|
||||
import { invokeIpc } from '@/lib/api-client';
|
||||
|
||||
export interface UpdateInfo {
|
||||
version: string;
|
||||
@@ -63,7 +64,7 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
||||
|
||||
// Get current version
|
||||
try {
|
||||
const version = await window.electron.ipcRenderer.invoke('update:version');
|
||||
const version = await invokeIpc<string>('update:version');
|
||||
set({ currentVersion: version as string });
|
||||
} catch (error) {
|
||||
console.error('Failed to get version:', error);
|
||||
@@ -71,12 +72,12 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
||||
|
||||
// Get current status
|
||||
try {
|
||||
const status = await window.electron.ipcRenderer.invoke('update:status') as {
|
||||
const status = await invokeIpc<{
|
||||
status: UpdateStatus;
|
||||
info?: UpdateInfo;
|
||||
progress?: ProgressInfo;
|
||||
error?: string;
|
||||
};
|
||||
}>('update:status');
|
||||
set({
|
||||
status: status.status,
|
||||
updateInfo: status.info || null,
|
||||
@@ -117,7 +118,7 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
||||
|
||||
// Sync auto-download preference to the main process
|
||||
if (autoDownloadUpdate) {
|
||||
window.electron.ipcRenderer.invoke('update:setAutoDownload', true).catch(() => {});
|
||||
invokeIpc('update:setAutoDownload', true).catch(() => {});
|
||||
}
|
||||
|
||||
// Auto-check for updates on startup (respects user toggle)
|
||||
@@ -133,7 +134,7 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
||||
|
||||
try {
|
||||
const result = await Promise.race([
|
||||
window.electron.ipcRenderer.invoke('update:check'),
|
||||
invokeIpc('update:check'),
|
||||
new Promise((_, reject) => setTimeout(() => reject(new Error('Update check timed out')), 30000))
|
||||
]) as {
|
||||
success: boolean;
|
||||
@@ -172,10 +173,10 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
||||
set({ status: 'downloading', error: null });
|
||||
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('update:download') as {
|
||||
const result = await invokeIpc<{
|
||||
success: boolean;
|
||||
error?: string;
|
||||
};
|
||||
}>('update:download');
|
||||
|
||||
if (!result.success) {
|
||||
set({ status: 'error', error: result.error || 'Failed to download update' });
|
||||
@@ -186,12 +187,12 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
||||
},
|
||||
|
||||
installUpdate: () => {
|
||||
window.electron.ipcRenderer.invoke('update:install');
|
||||
void invokeIpc('update:install');
|
||||
},
|
||||
|
||||
cancelAutoInstall: async () => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('update:cancelAutoInstall');
|
||||
await invokeIpc('update:cancelAutoInstall');
|
||||
} catch (error) {
|
||||
console.error('Failed to cancel auto-install:', error);
|
||||
}
|
||||
@@ -199,7 +200,7 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
||||
|
||||
setChannel: async (channel) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('update:setChannel', channel);
|
||||
await invokeIpc('update:setChannel', channel);
|
||||
} catch (error) {
|
||||
console.error('Failed to set update channel:', error);
|
||||
}
|
||||
@@ -207,7 +208,7 @@ export const useUpdateStore = create<UpdateState>((set, get) => ({
|
||||
|
||||
setAutoDownload: async (enable) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('update:setAutoDownload', enable);
|
||||
await invokeIpc('update:setAutoDownload', enable);
|
||||
} catch (error) {
|
||||
console.error('Failed to set auto-download:', error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user