From af15c7c8e1a08419940d28b66f07bfaecade90aa Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Mon, 9 Feb 2026 09:07:51 +0530 Subject: [PATCH] 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. --- src-tauri/src/commands/runtime.rs | 1 + src-tauri/src/runtime/manifest.rs | 3 + src-tauri/src/runtime/qjs_skill_instance.rs | 2 +- src/components/SkillsGrid.tsx | 61 ++++++++++++--------- src/utils/desktopDeepLinkListener.ts | 6 +- 5 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src-tauri/src/commands/runtime.rs b/src-tauri/src/commands/runtime.rs index 98482c287..47c0b6ecb 100644 --- a/src-tauri/src/commands/runtime.rs +++ b/src-tauri/src/commands/runtime.rs @@ -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!({ diff --git a/src-tauri/src/runtime/manifest.rs b/src-tauri/src/runtime/manifest.rs index b3e3d7833..60e9eac4d 100644 --- a/src-tauri/src/runtime/manifest.rs +++ b/src-tauri/src/runtime/manifest.rs @@ -37,6 +37,9 @@ pub struct SkillManifest { pub auto_start: bool, /// Version string (informational). pub version: Option, + /// Whether to ignore in production. + #[serde(default)] + pub ignoreInProduction: bool, /// Description (informational). pub description: Option, /// Setup configuration (optional). diff --git a/src-tauri/src/runtime/qjs_skill_instance.rs b/src-tauri/src/runtime/qjs_skill_instance.rs index 6b784ee3e..0b0b1abe9 100644 --- a/src-tauri/src/runtime/qjs_skill_instance.rs +++ b/src-tauri/src/runtime/qjs_skill_instance.rs @@ -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"; }})()"# diff --git a/src/components/SkillsGrid.tsx b/src/components/SkillsGrid.tsx index 23b3aebdb..ca49e03d8 100644 --- a/src/components/SkillsGrid.tsx +++ b/src/components/SkillsGrid.tsx @@ -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 | 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 | 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 diff --git a/src/utils/desktopDeepLinkListener.ts b/src/utils/desktopDeepLinkListener.ts index 66d0e7f00..c0ebe068f 100644 --- a/src/utils/desktopDeepLinkListener.ts +++ b/src/utils/desktopDeepLinkListener.ts @@ -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 } ).__simulateDeepLink = (url: string) => handleDeepLinkUrls([url]);