mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-30 15:03:57 +00:00
refactor(tauri): reduce desktop host to sidecar lifecycle + deep-link (#84)
* feat(onboarding): introduce DEV_FORCE_ONBOARDING flag to control onboarding flow - Added DEV_FORCE_ONBOARDING configuration to bypass onboarding checks during development. - Updated onboarding logic in AppRoutes to respect the new flag, ensuring onboarding is always shown when enabled. - Introduced new utility functions for managing onboarding state based on the flag. - Updated Cargo.lock and Cargo.toml to reflect dependency changes and version updates. - Removed deprecated openhuman command module and refactored related functionalities into daemon_host module for better organization. * feat(daemon): refactor daemon health monitoring and window management - Updated DaemonHealthService to use polling via `openhuman.health_snapshot` instead of event listening for health updates. - Introduced a new focusMainWindow function to centralize window focus logic across deep link handling and Tauri commands. - Replaced `invoke` calls with direct window management methods for showing, hiding, and toggling the main window. - Removed deprecated core_rpc module and related commands for improved organization and clarity. - Updated Cargo.toml and Cargo.lock to reflect dependency changes. * refactor(daemonHealthService): streamline imports and simplify tool object structure - Moved the import of `callCoreRpc` to a more appropriate location in DaemonHealthService. - Simplified the structure of the tools object in the aiGetConfig function for better readability. - Ensured consistency in Tauri command invocations by removing unnecessary line breaks.
This commit is contained in:
@@ -5,5 +5,9 @@ export const CORE_RPC_URL =
|
||||
|
||||
export const IS_DEV = import.meta.env.DEV;
|
||||
|
||||
/** Dev only: skip `.skip_onboarding` workspace check and ignore onboarded state so `/onboarding` always shows. Set `VITE_DEV_FORCE_ONBOARDING=true` in `.env.local`. */
|
||||
export const DEV_FORCE_ONBOARDING =
|
||||
import.meta.env.DEV && import.meta.env.VITE_DEV_FORCE_ONBOARDING === 'true';
|
||||
|
||||
export const SKILLS_GITHUB_REPO =
|
||||
import.meta.env.VITE_SKILLS_GITHUB_REPO || 'tinyhumansai/openhuman-skills';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isTauri as coreIsTauri, invoke } from '@tauri-apps/api/core';
|
||||
import { isTauri as coreIsTauri } from '@tauri-apps/api/core';
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||
import { getCurrent, onOpenUrl } from '@tauri-apps/plugin-deep-link';
|
||||
|
||||
import { skillManager } from '../lib/skills/manager';
|
||||
@@ -35,6 +36,17 @@ function getCurrentUserId(): string | null {
|
||||
}
|
||||
}
|
||||
|
||||
const focusMainWindow = async () => {
|
||||
try {
|
||||
const window = getCurrentWindow();
|
||||
await window.show();
|
||||
await window.unminimize();
|
||||
await window.setFocus();
|
||||
} catch (err) {
|
||||
console.warn('[DeepLink] Failed to focus window:', err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle an `openhuman://auth?token=...` deep link for login.
|
||||
*/
|
||||
@@ -48,11 +60,7 @@ const handleAuthDeepLink = async (parsed: URL) => {
|
||||
|
||||
console.log('[DeepLink] Received auth token', token);
|
||||
|
||||
try {
|
||||
await invoke('show_window');
|
||||
} catch (err) {
|
||||
console.warn('[DeepLink] Failed to show window:', err);
|
||||
}
|
||||
await focusMainWindow();
|
||||
|
||||
if (key === 'auth') {
|
||||
store.dispatch(setToken(token));
|
||||
@@ -72,11 +80,7 @@ const handleAuthDeepLink = async (parsed: URL) => {
|
||||
const handlePaymentDeepLink = async (parsed: URL) => {
|
||||
const path = parsed.pathname.replace(/^\/+/, '');
|
||||
|
||||
try {
|
||||
await invoke('show_window');
|
||||
} catch {
|
||||
// Not fatal
|
||||
}
|
||||
await focusMainWindow();
|
||||
|
||||
if (path === 'success') {
|
||||
const sessionId = parsed.searchParams.get('session_id');
|
||||
@@ -110,11 +114,7 @@ const handleOAuthDeepLink = async (parsed: URL) => {
|
||||
// pathname is "/success" or "/error" (hostname is "oauth")
|
||||
const path = parsed.pathname.replace(/^\/+/, '');
|
||||
|
||||
try {
|
||||
await invoke('show_window');
|
||||
} catch {
|
||||
// Not fatal
|
||||
}
|
||||
await focusMainWindow();
|
||||
|
||||
if (path === 'success') {
|
||||
const integrationId = parsed.searchParams.get('integrationId');
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Helper functions for invoking Tauri commands from the frontend.
|
||||
*/
|
||||
import { isTauri as coreIsTauri, invoke } from '@tauri-apps/api/core';
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||
|
||||
import { callCoreRpc } from '../services/coreRpcClient';
|
||||
|
||||
@@ -86,7 +87,10 @@ export async function showWindow(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('show_window');
|
||||
const window = getCurrentWindow();
|
||||
await window.show();
|
||||
await window.unminimize();
|
||||
await window.setFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +101,7 @@ export async function hideWindow(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('hide_window');
|
||||
await getCurrentWindow().hide();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +112,15 @@ export async function toggleWindow(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('toggle_window');
|
||||
const window = getCurrentWindow();
|
||||
const visible = await window.isVisible();
|
||||
if (visible) {
|
||||
await window.hide();
|
||||
return;
|
||||
}
|
||||
await window.show();
|
||||
await window.unminimize();
|
||||
await window.setFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +131,7 @@ export async function isWindowVisible(): Promise<boolean> {
|
||||
return true; // In browser, window is always visible
|
||||
}
|
||||
|
||||
return await invoke('is_window_visible');
|
||||
return await getCurrentWindow().isVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,7 +142,7 @@ export async function minimizeWindow(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('minimize_window');
|
||||
await getCurrentWindow().minimize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +153,8 @@ export async function maximizeWindow(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('maximize_window');
|
||||
const window = getCurrentWindow();
|
||||
await window.toggleMaximize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,7 +165,7 @@ export async function closeWindow(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('close_window');
|
||||
await getCurrentWindow().close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,7 +177,7 @@ export async function setWindowTitle(title: string): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
await invoke('set_window_title', { title });
|
||||
await getCurrentWindow().setTitle(title);
|
||||
}
|
||||
|
||||
// --- Memory Commands ---
|
||||
@@ -348,10 +361,6 @@ export interface CommandResponse<T> {
|
||||
logs: string[];
|
||||
}
|
||||
|
||||
function wrapCommandResult<T>(result: T): CommandResponse<T> {
|
||||
return { result, logs: [] };
|
||||
}
|
||||
|
||||
export interface SkillSnapshot {
|
||||
skill_id: string;
|
||||
name: string;
|
||||
@@ -1254,17 +1263,28 @@ export async function openhumanLocalAiDownloadAsset(
|
||||
}
|
||||
|
||||
export async function aiGetConfig(): Promise<AIPreview> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await invoke('ai_get_config');
|
||||
return {
|
||||
soul: {
|
||||
raw: '',
|
||||
name: 'OpenHuman',
|
||||
description: 'AI assistant',
|
||||
personalityPreview: [],
|
||||
safetyRulesPreview: [],
|
||||
loadedAt: Date.now(),
|
||||
},
|
||||
tools: { raw: '', totalTools: 0, activeSkills: 0, skillsPreview: [], loadedAt: Date.now() },
|
||||
metadata: {
|
||||
loadedAt: Date.now(),
|
||||
loadingDuration: 0,
|
||||
hasFallbacks: true,
|
||||
sources: { soul: 'frontend', tools: 'frontend' },
|
||||
errors: ['AI prompt preview has been moved out of the Tauri host.'],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function aiRefreshConfig(): Promise<AIPreview> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await invoke('ai_refresh_config');
|
||||
return aiGetConfig();
|
||||
}
|
||||
|
||||
export async function openhumanEncryptSecret(plaintext: string): Promise<CommandResponse<string>> {
|
||||
@@ -1344,44 +1364,36 @@ export async function openhumanServiceInstall(): Promise<CommandResponse<Service
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await invoke<CommandResponse<ServiceStatus>>('core_rpc_relay', {
|
||||
request: { method: 'openhuman.service_install', params: {} },
|
||||
});
|
||||
return await callCoreRpc<CommandResponse<ServiceStatus>>({ method: 'openhuman.service_install' });
|
||||
}
|
||||
|
||||
export async function openhumanServiceStart(): Promise<CommandResponse<ServiceStatus>> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await invoke<CommandResponse<ServiceStatus>>('core_rpc_relay', {
|
||||
request: { method: 'openhuman.service_start', params: {} },
|
||||
});
|
||||
return await callCoreRpc<CommandResponse<ServiceStatus>>({ method: 'openhuman.service_start' });
|
||||
}
|
||||
|
||||
export async function openhumanServiceStop(): Promise<CommandResponse<ServiceStatus>> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await invoke<CommandResponse<ServiceStatus>>('core_rpc_relay', {
|
||||
request: { method: 'openhuman.service_stop', params: {} },
|
||||
});
|
||||
return await callCoreRpc<CommandResponse<ServiceStatus>>({ method: 'openhuman.service_stop' });
|
||||
}
|
||||
|
||||
export async function openhumanServiceStatus(): Promise<CommandResponse<ServiceStatus>> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await invoke<CommandResponse<ServiceStatus>>('core_rpc_relay', {
|
||||
request: { method: 'openhuman.service_status', params: {} },
|
||||
});
|
||||
return await callCoreRpc<CommandResponse<ServiceStatus>>({ method: 'openhuman.service_status' });
|
||||
}
|
||||
|
||||
export async function openhumanServiceUninstall(): Promise<CommandResponse<ServiceStatus>> {
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await invoke<CommandResponse<ServiceStatus>>('core_rpc_relay', {
|
||||
request: { method: 'openhuman.service_uninstall', params: {} },
|
||||
return await callCoreRpc<CommandResponse<ServiceStatus>>({
|
||||
method: 'openhuman.service_uninstall',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1389,8 +1401,8 @@ export async function openhumanAgentServerStatus(): Promise<CommandResponse<Agen
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
return await invoke<CommandResponse<AgentServerStatus>>('core_rpc_relay', {
|
||||
request: { method: 'openhuman.agent_server_status', params: {} },
|
||||
return await callCoreRpc<CommandResponse<AgentServerStatus>>({
|
||||
method: 'openhuman.agent_server_status',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1398,8 +1410,9 @@ export async function openhumanGetDaemonHostConfig(): Promise<CommandResponse<Da
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
const result = await invoke<DaemonHostConfig>('openhuman_get_daemon_host_config');
|
||||
return wrapCommandResult(result);
|
||||
return await callCoreRpc<CommandResponse<DaemonHostConfig>>({
|
||||
method: 'openhuman.service_daemon_host_get',
|
||||
});
|
||||
}
|
||||
|
||||
export async function openhumanSetDaemonHostConfig(
|
||||
@@ -1408,8 +1421,10 @@ export async function openhumanSetDaemonHostConfig(
|
||||
if (!isTauri()) {
|
||||
throw new Error('Not running in Tauri');
|
||||
}
|
||||
const result = await invoke<DaemonHostConfig>('openhuman_set_daemon_host_config', { showTray });
|
||||
return wrapCommandResult(result);
|
||||
return await callCoreRpc<CommandResponse<DaemonHostConfig>>({
|
||||
method: 'openhuman.service_daemon_host_set',
|
||||
params: { show_tray: showTray },
|
||||
});
|
||||
}
|
||||
|
||||
export async function openhumanAccessibilityStatus(): Promise<
|
||||
|
||||
Reference in New Issue
Block a user