mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
Enhance SkillsGrid and Manifest Handling
- Added `ignoreInProduction` property to `SkillListEntry` and updated processing logic to filter skills based on the `IS_DEV` flag. - Updated Rust structures in the Tauri backend to include `ignoreInProduction` in the skill manifest. - Refactored desktop deep link listener to remove unnecessary `IS_DEV` checks. - Improved JSON serialization handling in QuickJS skill instance.
This commit is contained in:
@@ -64,6 +64,7 @@ mod desktop {
|
||||
"entry": m.entry,
|
||||
"autoStart": m.auto_start,
|
||||
"version": m.version,
|
||||
"ignoreInProduction": m.ignoreInProduction,
|
||||
"description": m.description,
|
||||
"setup": m.setup.as_ref().map(|s| {
|
||||
let mut obj = serde_json::json!({
|
||||
|
||||
@@ -37,6 +37,9 @@ pub struct SkillManifest {
|
||||
pub auto_start: bool,
|
||||
/// Version string (informational).
|
||||
pub version: Option<String>,
|
||||
/// Whether to ignore in production.
|
||||
#[serde(default)]
|
||||
pub ignoreInProduction: bool,
|
||||
/// Description (informational).
|
||||
pub description: Option<String>,
|
||||
/// Setup configuration (optional).
|
||||
|
||||
@@ -672,7 +672,7 @@ async fn handle_js_call(
|
||||
if (typeof fn === 'function') {{
|
||||
var args = {args_json};
|
||||
var result = fn.call(skill, args);
|
||||
return JSON.stringify(result);
|
||||
return JSON.stringify(result === undefined ? null : result);
|
||||
}}
|
||||
return "null";
|
||||
}})()"#
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useSkillConnectionStatus } from '../lib/skills/hooks';
|
||||
import { skillManager } from '../lib/skills/manager';
|
||||
import type { SkillConnectionStatus, SkillHostConnectionState } from '../lib/skills/types';
|
||||
import { useAppSelector } from '../store/hooks';
|
||||
import { IS_DEV } from '../utils/config';
|
||||
import SkillSetupModal from './skills/SkillSetupModal';
|
||||
|
||||
// Map skill IDs to icons
|
||||
@@ -109,6 +110,7 @@ interface SkillListEntry {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
ignoreInProduction?: boolean;
|
||||
icon?: React.ReactElement;
|
||||
hasSetup: boolean;
|
||||
}
|
||||
@@ -322,18 +324,21 @@ export default function SkillsGrid() {
|
||||
return true;
|
||||
});
|
||||
|
||||
const processed: SkillListEntry[] = validManifests.map(m => {
|
||||
const setup = m.setup as Record<string, unknown> | undefined;
|
||||
return {
|
||||
id: m.id as string,
|
||||
name:
|
||||
(m.name as string) ||
|
||||
(m.id as string).charAt(0).toUpperCase() + (m.id as string).slice(1),
|
||||
description: (m.description as string) || '',
|
||||
icon: SKILL_ICONS[m.id as string],
|
||||
hasSetup: !!(setup && setup.required),
|
||||
};
|
||||
});
|
||||
const processed: SkillListEntry[] = validManifests
|
||||
.map(m => {
|
||||
const setup = m.setup as Record<string, unknown> | undefined;
|
||||
return {
|
||||
id: m.id as string,
|
||||
name:
|
||||
(m.name as string) ||
|
||||
(m.id as string).charAt(0).toUpperCase() + (m.id as string).slice(1),
|
||||
description: (m.description as string) || '',
|
||||
icon: SKILL_ICONS[m.id as string],
|
||||
ignoreInProduction: (m.ignoreInProduction as boolean) ?? false,
|
||||
hasSetup: !!(setup && setup.required),
|
||||
};
|
||||
})
|
||||
.filter(s => IS_DEV || !s.ignoreInProduction);
|
||||
|
||||
setSkillsList(processed);
|
||||
setLoading(false);
|
||||
@@ -348,25 +353,27 @@ export default function SkillsGrid() {
|
||||
|
||||
// Sort skills by connection status (connected first)
|
||||
const sortedSkillsList = useMemo(() => {
|
||||
return [...skillsList].sort((a, b) => {
|
||||
const skillA = skillsState[a.id];
|
||||
const skillB = skillsState[b.id];
|
||||
const stateA = skillStates[a.id];
|
||||
const stateB = skillStates[b.id];
|
||||
return [...skillsList]
|
||||
.sort((a, b) => {
|
||||
const skillA = skillsState[a.id];
|
||||
const skillB = skillsState[b.id];
|
||||
const stateA = skillStates[a.id];
|
||||
const stateB = skillStates[b.id];
|
||||
|
||||
const statusA = deriveConnectionStatus(skillA?.status, skillA?.setupComplete, stateA);
|
||||
const statusB = deriveConnectionStatus(skillB?.status, skillB?.setupComplete, stateB);
|
||||
const statusA = deriveConnectionStatus(skillA?.status, skillA?.setupComplete, stateA);
|
||||
const statusB = deriveConnectionStatus(skillB?.status, skillB?.setupComplete, stateB);
|
||||
|
||||
const priorityA = STATUS_PRIORITY[statusA] ?? 999;
|
||||
const priorityB = STATUS_PRIORITY[statusB] ?? 999;
|
||||
const priorityA = STATUS_PRIORITY[statusA] ?? 999;
|
||||
const priorityB = STATUS_PRIORITY[statusB] ?? 999;
|
||||
|
||||
// If same priority, sort alphabetically by name
|
||||
if (priorityA === priorityB) {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
// If same priority, sort alphabetically by name
|
||||
if (priorityA === priorityB) {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
|
||||
return priorityA - priorityB;
|
||||
});
|
||||
return priorityA - priorityB;
|
||||
})
|
||||
.filter(s => IS_DEV || !s.ignoreInProduction);
|
||||
}, [skillsList, skillsState, skillStates]);
|
||||
|
||||
// Show mobile-only message on mobile platforms
|
||||
|
||||
@@ -5,7 +5,6 @@ import { skillManager } from '../lib/skills/manager';
|
||||
import { consumeLoginToken } from '../services/api/authApi';
|
||||
import { store } from '../store';
|
||||
import { setToken } from '../store/authSlice';
|
||||
import { IS_DEV } from './config';
|
||||
|
||||
/**
|
||||
* Handle an `alphahuman://auth?token=...` deep link for login.
|
||||
@@ -126,8 +125,9 @@ export const setupDesktopDeepLinkListener = async () => {
|
||||
void handleDeepLinkUrls(urls);
|
||||
});
|
||||
|
||||
if (IS_DEV && typeof window !== 'undefined') {
|
||||
// window.__simulateDeepLink('alphahuman//auth?token=1234567890')
|
||||
if (typeof window !== 'undefined') {
|
||||
// window.__simulateDeepLink('alphahuman://auth?token=1234567890')
|
||||
// window.__simulateDeepLink('alphahuman://oauth/success?integrationId=6989178fad6dbfe9b137f577&skillId=notion')
|
||||
(
|
||||
window as Window & { __simulateDeepLink?: (url: string) => Promise<void> }
|
||||
).__simulateDeepLink = (url: string) => handleDeepLinkUrls([url]);
|
||||
|
||||
Reference in New Issue
Block a user