From 403f239ca58ee0f9347ca096deeacbe03b20cdc9 Mon Sep 17 00:00:00 2001 From: Steven Enamakel <31011319+senamakel@users.noreply.github.com> Date: Sat, 11 Apr 2026 14:57:35 -0700 Subject: [PATCH] refactor: remove QuickJS skills runtime (#508) * refactor: remove quickjs skills runtime * style: apply repo formatting * refactor: clean up error reporting and connection handling - Removed the 'skill' source option from the error report structure to streamline error reporting. - Refactored the ConnectionsPanel component to simplify connection status badge rendering and improve clarity. - Updated the CronJobsPanel to enhance logging for cron job loading processes. - Adjusted SkillCard component to use a more consistent type for icons. - Deleted outdated end-to-end tests for Gmail and Notion skills, improving test suite maintainability. * fix: remove unnecessary ESLint disable comment in Conversations component - Cleaned up the Conversations component by removing the ESLint disable comment for exhaustive dependencies in the useEffect hook, improving code clarity and maintainability. * fix: remove unnecessary whitespace in Conversations component - Eliminated an extra line of whitespace in the Conversations component, enhancing code readability and maintainability. * refactor: streamline SkillCard imports for improved clarity - Combined import statements in the SkillCard component to enhance code readability and maintainability. --- Cargo.lock | 31 +- Cargo.toml | 1 - app/src-tauri/Cargo.lock | 2 +- .../components/ErrorReportNotification.tsx | 5 - app/src/components/settings/SettingsHome.tsx | 11 +- .../settings/panels/ConnectionsPanel.tsx | 118 +- .../settings/panels/CronJobsPanel.tsx | 216 +-- .../settings/panels/RecoveryPhrasePanel.tsx | 5 - .../panels/cron/RuntimeSkillCronList.tsx | 173 --- .../components/skills/AuthModeSelector.tsx | 139 -- .../components/skills/SetupFormRenderer.tsx | 269 ---- app/src/components/skills/SkillCard.tsx | 212 +-- app/src/components/skills/SkillDebugModal.tsx | 385 ----- .../skills/SkillManagementPanel.tsx | 323 ---- app/src/components/skills/SkillSetupModal.tsx | 188 --- .../components/skills/SkillSetupWizard.tsx | 992 ------------ app/src/components/skills/shared.tsx | 175 --- .../useAutocompleteSkillStatus.ts | 2 +- .../useScreenIntelligenceSkillStatus.ts | 2 +- app/src/features/voice/useVoiceSkillStatus.ts | 2 +- app/src/lib/composio/composioApi.ts | 5 +- app/src/lib/skills/hooks.ts | 280 ---- app/src/lib/skills/index.ts | 7 - app/src/lib/skills/manager.ts | 719 --------- app/src/lib/skills/paths.ts | 39 - app/src/lib/skills/runtime.ts | 233 --- app/src/lib/skills/skillEvents.ts | 52 - app/src/lib/skills/skillsApi.ts | 201 --- app/src/lib/skills/sync.ts | 38 - app/src/lib/skills/transport.ts | 102 -- app/src/lib/skills/types.ts | 245 --- app/src/pages/Conversations.tsx | 1 - app/src/pages/Mnemonic.tsx | 5 - app/src/pages/__tests__/skillsSyncUi.test.ts | 58 - app/src/pages/onboarding/steps/SkillsStep.tsx | 147 +- app/src/pages/skillsSyncUi.ts | 179 --- app/src/services/errorReportQueue.ts | 4 +- app/src/services/socketService.ts | 5 - app/src/types/skillStatus.ts | 8 + app/src/utils/desktopDeepLinkListener.ts | 44 +- app/src/utils/tauriCommands/index.ts | 1 - app/src/utils/tauriCommands/skills.ts | 172 --- app/test/Mnemonic.test.tsx | 55 +- src/core/all.rs | 3 - src/core/cli.rs | 1 - src/core/jsonrpc.rs | 87 +- src/core/mod.rs | 1 - src/core/skills_cli.rs | 541 ------- .../agent/agents/skills_agent/agent.toml | 2 +- .../agent/agents/skills_agent/prompt.md | 5 +- .../agent/harness/session/builder.rs | 11 - src/openhuman/composio/tools.rs | 4 +- src/openhuman/skills/bridge/mod.rs | 8 - src/openhuman/skills/bridge/net.rs | 112 -- src/openhuman/skills/bus.rs | 80 +- src/openhuman/skills/cron_scheduler.rs | 235 --- src/openhuman/skills/manifest.rs | 332 ---- src/openhuman/skills/mod.rs | 29 +- src/openhuman/skills/paths.rs | 173 --- src/openhuman/skills/ping_scheduler.rs | 252 --- src/openhuman/skills/preferences.rs | 197 --- src/openhuman/skills/qjs_engine.rs | 1004 ------------ .../qjs_skill_instance/event_loop/mod.rs | 950 ------------ .../event_loop/rpc_handlers.rs | 560 ------- .../event_loop/webhook_handler.rs | 112 -- .../skills/qjs_skill_instance/instance.rs | 308 ---- .../skills/qjs_skill_instance/js_handlers.rs | 759 --------- .../skills/qjs_skill_instance/js_helpers.rs | 246 --- .../skills/qjs_skill_instance/mod.rs | 19 - .../skills/qjs_skill_instance/types.rs | 74 - .../skills/quickjs_libs/bootstrap.js | 1366 ----------------- src/openhuman/skills/quickjs_libs/mod.rs | 11 - .../skills/quickjs_libs/qjs_ops/mod.rs | 22 - .../skills/quickjs_libs/qjs_ops/ops.rs | 33 - .../skills/quickjs_libs/qjs_ops/ops_core.rs | 218 --- .../skills/quickjs_libs/qjs_ops/ops_net.rs | 208 --- .../skills/quickjs_libs/qjs_ops/ops_state.rs | 219 --- .../quickjs_libs/qjs_ops/ops_storage.rs | 369 ----- .../quickjs_libs/qjs_ops/ops_webhook.rs | 96 -- .../skills/quickjs_libs/qjs_ops/types.rs | 178 --- src/openhuman/skills/quickjs_libs/storage.rs | 709 --------- src/openhuman/skills/registry_cache.rs | 95 -- src/openhuman/skills/registry_ops.rs | 876 ----------- src/openhuman/skills/registry_types.rs | 241 --- src/openhuman/skills/schemas.rs | 1133 -------------- src/openhuman/skills/skill_registry.rs | 575 ------- src/openhuman/skills/types.rs | 486 +----- src/openhuman/skills/utils.rs | 155 -- src/openhuman/skills/working_memory.rs | 649 -------- .../subconscious/situation_report.rs | 65 +- src/openhuman/tools/impl/agent/mod.rs | 26 +- .../tools/impl/agent/spawn_subagent.rs | 58 +- src/openhuman/tools/impl/network/mod.rs | 2 - .../tools/impl/network/skill_bridge.rs | 199 --- src/openhuman/tools/mod.rs | 2 +- src/openhuman/tools/orchestrator_tools.rs | 49 +- src/openhuman/tools/traits.rs | 19 +- src/openhuman/webhooks/bus.rs | 131 +- src/openhuman/webhooks/ops.rs | 26 +- tests/json_rpc_e2e.rs | 717 --------- tests/skills_debug_e2e.rs | 777 ---------- tests/skills_gmail_e2e.rs | 941 ------------ tests/skills_gmail_oauth_proxy_rpc_e2e.rs | 405 ----- tests/skills_notion_live.rs | 408 ----- tests/skills_rpc_e2e.rs | 361 ----- tests/skills_sync_memory_test.rs | 418 ----- 106 files changed, 160 insertions(+), 24039 deletions(-) delete mode 100644 app/src/components/settings/panels/cron/RuntimeSkillCronList.tsx delete mode 100644 app/src/components/skills/AuthModeSelector.tsx delete mode 100644 app/src/components/skills/SetupFormRenderer.tsx delete mode 100644 app/src/components/skills/SkillDebugModal.tsx delete mode 100644 app/src/components/skills/SkillManagementPanel.tsx delete mode 100644 app/src/components/skills/SkillSetupModal.tsx delete mode 100644 app/src/components/skills/SkillSetupWizard.tsx delete mode 100644 app/src/components/skills/shared.tsx delete mode 100644 app/src/lib/skills/hooks.ts delete mode 100644 app/src/lib/skills/index.ts delete mode 100644 app/src/lib/skills/manager.ts delete mode 100644 app/src/lib/skills/paths.ts delete mode 100644 app/src/lib/skills/runtime.ts delete mode 100644 app/src/lib/skills/skillEvents.ts delete mode 100644 app/src/lib/skills/skillsApi.ts delete mode 100644 app/src/lib/skills/sync.ts delete mode 100644 app/src/lib/skills/transport.ts delete mode 100644 app/src/lib/skills/types.ts delete mode 100644 app/src/pages/__tests__/skillsSyncUi.test.ts delete mode 100644 app/src/pages/skillsSyncUi.ts create mode 100644 app/src/types/skillStatus.ts delete mode 100644 app/src/utils/tauriCommands/skills.ts delete mode 100644 src/core/skills_cli.rs delete mode 100644 src/openhuman/skills/bridge/mod.rs delete mode 100644 src/openhuman/skills/bridge/net.rs delete mode 100644 src/openhuman/skills/cron_scheduler.rs delete mode 100644 src/openhuman/skills/manifest.rs delete mode 100644 src/openhuman/skills/paths.rs delete mode 100644 src/openhuman/skills/ping_scheduler.rs delete mode 100644 src/openhuman/skills/preferences.rs delete mode 100644 src/openhuman/skills/qjs_engine.rs delete mode 100644 src/openhuman/skills/qjs_skill_instance/event_loop/mod.rs delete mode 100644 src/openhuman/skills/qjs_skill_instance/event_loop/rpc_handlers.rs delete mode 100644 src/openhuman/skills/qjs_skill_instance/event_loop/webhook_handler.rs delete mode 100644 src/openhuman/skills/qjs_skill_instance/instance.rs delete mode 100644 src/openhuman/skills/qjs_skill_instance/js_handlers.rs delete mode 100644 src/openhuman/skills/qjs_skill_instance/js_helpers.rs delete mode 100644 src/openhuman/skills/qjs_skill_instance/mod.rs delete mode 100644 src/openhuman/skills/qjs_skill_instance/types.rs delete mode 100644 src/openhuman/skills/quickjs_libs/bootstrap.js delete mode 100644 src/openhuman/skills/quickjs_libs/mod.rs delete mode 100644 src/openhuman/skills/quickjs_libs/qjs_ops/mod.rs delete mode 100644 src/openhuman/skills/quickjs_libs/qjs_ops/ops.rs delete mode 100644 src/openhuman/skills/quickjs_libs/qjs_ops/ops_core.rs delete mode 100644 src/openhuman/skills/quickjs_libs/qjs_ops/ops_net.rs delete mode 100644 src/openhuman/skills/quickjs_libs/qjs_ops/ops_state.rs delete mode 100644 src/openhuman/skills/quickjs_libs/qjs_ops/ops_storage.rs delete mode 100644 src/openhuman/skills/quickjs_libs/qjs_ops/ops_webhook.rs delete mode 100644 src/openhuman/skills/quickjs_libs/qjs_ops/types.rs delete mode 100644 src/openhuman/skills/quickjs_libs/storage.rs delete mode 100644 src/openhuman/skills/registry_cache.rs delete mode 100644 src/openhuman/skills/registry_ops.rs delete mode 100644 src/openhuman/skills/registry_types.rs delete mode 100644 src/openhuman/skills/schemas.rs delete mode 100644 src/openhuman/skills/skill_registry.rs delete mode 100644 src/openhuman/skills/utils.rs delete mode 100644 src/openhuman/skills/working_memory.rs delete mode 100644 src/openhuman/tools/impl/network/skill_bridge.rs delete mode 100644 tests/skills_debug_e2e.rs delete mode 100644 tests/skills_gmail_e2e.rs delete mode 100644 tests/skills_gmail_oauth_proxy_rpc_e2e.rs delete mode 100644 tests/skills_notion_live.rs delete mode 100644 tests/skills_rpc_e2e.rs delete mode 100644 tests/skills_sync_memory_test.rs diff --git a/Cargo.lock b/Cargo.lock index 893358f54..4e4224f00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4632,7 +4632,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openhuman" -version = "0.52.4" +version = "0.52.5" dependencies = [ "aes-gcm", "anyhow", @@ -4687,7 +4687,6 @@ dependencies = [ "reqwest 0.12.28", "ring", "rppal", - "rquickjs", "rusqlite", "rustls", "rustls-pki-types", @@ -5894,34 +5893,6 @@ dependencies = [ "libc", ] -[[package]] -name = "rquickjs" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5227859c4dfc83f428e58f9569bf439e628c8d139020e7faff437e6f5abaa0" -dependencies = [ - "rquickjs-core", -] - -[[package]] -name = "rquickjs-core" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82e0ca83028ad5b533b53b96c395bbaab905a5774de4aaf1004eeacafa3d85d" -dependencies = [ - "async-lock", - "rquickjs-sys", -] - -[[package]] -name = "rquickjs-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fed0097b0b4fbb2a87f6dd3b995a7c64ca56de30007eb7e867dfdfc78324ba5" -dependencies = [ - "cc", -] - [[package]] name = "ruma" version = "0.14.1" diff --git a/Cargo.toml b/Cargo.toml index a4dc9b03f..441155bce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ name = "openhuman_core" crate-type = ["rlib"] [dependencies] -rquickjs = { version = "0.9", features = ["futures", "parallel"] } serde = { version = "1", features = ["derive"] } serde_json = "1" reqwest = { version = "0.12", default-features = false, features = ["json", "blocking", "rustls-tls", "native-tls", "stream", "http2", "multipart", "socks"] } diff --git a/app/src-tauri/Cargo.lock b/app/src-tauri/Cargo.lock index b91fb37eb..d60624975 100644 --- a/app/src-tauri/Cargo.lock +++ b/app/src-tauri/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "OpenHuman" -version = "0.52.4" +version = "0.52.5" dependencies = [ "env_logger", "log", diff --git a/app/src/components/ErrorReportNotification.tsx b/app/src/components/ErrorReportNotification.tsx index 2c82055dd..7f84041c0 100644 --- a/app/src/components/ErrorReportNotification.tsx +++ b/app/src/components/ErrorReportNotification.tsx @@ -110,11 +110,6 @@ function NotificationCard({ DEV )} - {report.source === 'skill' && ( - - SKILL - - )}

{report.message}

diff --git a/app/src/components/settings/SettingsHome.tsx b/app/src/components/settings/SettingsHome.tsx index c7a1208c4..144bb10f1 100644 --- a/app/src/components/settings/SettingsHome.tsx +++ b/app/src/components/settings/SettingsHome.tsx @@ -1,6 +1,5 @@ import { useState } from 'react'; -import { skillManager } from '../../lib/skills/manager'; import { useCoreState } from '../../providers/CoreStateProvider'; import { persistor } from '../../store'; import { resetOpenHumanDataAndRestartCore } from '../../utils/tauriCommands'; @@ -43,14 +42,6 @@ const SettingsHome = () => { throw err; } - // Best-effort cleanup for in-memory and browser-side caches that live outside the Rust core. - try { - await skillManager.clearAllSkillsData(); - } catch (error) { - console.warn('Failed to clear skills data:', error); - // Continue even if skill cleanup fails because the backend reset already completed. - } - await persistor.purge(); window.localStorage.clear(); window.sessionStorage.clear(); @@ -247,7 +238,7 @@ const SettingsHome = () => {

This will sign you out and permanently delete local app data including:

diff --git a/app/src/components/settings/panels/ConnectionsPanel.tsx b/app/src/components/settings/panels/ConnectionsPanel.tsx index 55e3b1e3e..66c5ecf51 100644 --- a/app/src/components/settings/panels/ConnectionsPanel.tsx +++ b/app/src/components/settings/panels/ConnectionsPanel.tsx @@ -1,11 +1,9 @@ -import { useState } from 'react'; +import type { ReactElement } from 'react'; import BinanceIcon from '../../../assets/icons/binance.svg'; import GoogleIcon from '../../../assets/icons/GoogleIcon'; import MetamaskIcon from '../../../assets/icons/metamask.svg'; import NotionIcon from '../../../assets/icons/notion.svg'; -import type { SkillConnectionStatus } from '../../../lib/skills/types'; -import SkillSetupModal from '../../skills/SkillSetupModal'; import SettingsHeader from '../components/SettingsHeader'; import { useSettingsNavigation } from '../hooks/useSettingsNavigation'; @@ -13,63 +11,11 @@ interface ConnectOption { id: string; name: string; description: string; - icon: React.ReactElement; + icon: ReactElement; comingSoon?: boolean; skillId?: string; } -// --------------------------------------------------------------------------- -// Status badge mapping -// --------------------------------------------------------------------------- - -const STATUS_BADGE_CONFIG: Record< - SkillConnectionStatus, - { label: string; bg: string; text: string; border: string } -> = { - connected: { - label: 'Connected', - bg: 'bg-sage-500/20', - text: 'text-sage-400', - border: 'border-sage-500/30', - }, - connecting: { - label: 'Connecting...', - bg: 'bg-amber-500/20', - text: 'text-amber-400', - border: 'border-amber-500/30', - }, - not_authenticated: { - label: 'Not Authenticated', - bg: 'bg-amber-500/20', - text: 'text-amber-400', - border: 'border-amber-500/30', - }, - disconnected: { - label: 'Disconnected', - bg: 'bg-stone-500/20', - text: 'text-stone-400', - border: 'border-stone-500/30', - }, - error: { - label: 'Error', - bg: 'bg-coral-500/20', - text: 'text-coral-400', - border: 'border-coral-500/30', - }, - offline: { - label: 'Offline', - bg: 'bg-stone-500/20', - text: 'text-stone-400', - border: 'border-stone-500/30', - }, - setup_required: { - label: 'Setup Required', - bg: 'bg-primary-500/20', - text: 'text-primary-400', - border: 'border-primary-500/30', - }, -}; - /** * Renders a connection option row with its real-time status badge. * Uses useSkillConnectionStatus hook for skill-backed connections. @@ -85,31 +31,17 @@ function ConnectionOptionRow({ isLast: boolean; onConnect: (option: ConnectOption) => void; }) { - const connectionStatus = 'setup_required' as SkillConnectionStatus; const isDisabled = option.comingSoon; - let badge: React.ReactElement; - if (option.comingSoon) { - badge = ( - - Coming Soon - - ); - } else if (option.skillId) { - const config = STATUS_BADGE_CONFIG[connectionStatus]; - badge = ( - - {config.label} - - ); - } else { - badge = ( - - Connect - - ); - } + const badge = option.comingSoon ? ( + + Coming Soon + + ) : ( + + Connect + + ); return ( diff --git a/app/src/components/settings/panels/RecoveryPhrasePanel.tsx b/app/src/components/settings/panels/RecoveryPhrasePanel.tsx index 8baa39c0c..4ac3c955e 100644 --- a/app/src/components/settings/panels/RecoveryPhrasePanel.tsx +++ b/app/src/components/settings/panels/RecoveryPhrasePanel.tsx @@ -1,10 +1,8 @@ import { type KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { skillManager } from '../../../lib/skills/manager'; import { useCoreState } from '../../../providers/CoreStateProvider'; import { deriveAesKeyFromMnemonic, - deriveEvmAddressFromMnemonic, generateMnemonicPhrase, MNEMONIC_GENERATE_WORD_COUNT, validateMnemonicPhrase, @@ -177,14 +175,11 @@ const RecoveryPhrasePanel = () => { } const aesKey = deriveAesKeyFromMnemonic(phraseToUse); - const walletAddress = deriveEvmAddressFromMnemonic(phraseToUse); - if (!user?._id) { setError('User not loaded. Please sign in again or refresh the page.'); return; } await setEncryptionKey(aesKey); - await skillManager.setWalletAddress(walletAddress); setSuccess(true); } catch (e) { setError(e instanceof Error ? e.message : 'Something went wrong. Please try again.'); diff --git a/app/src/components/settings/panels/cron/RuntimeSkillCronList.tsx b/app/src/components/settings/panels/cron/RuntimeSkillCronList.tsx deleted file mode 100644 index adfd17ce2..000000000 --- a/app/src/components/settings/panels/cron/RuntimeSkillCronList.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import type { RuntimeSkillOption } from '../../../../utils/tauriCommands'; - -interface CronSkillConfig { - skillId: string; - name: string; - enabled: boolean; - manifestTickInterval: number | null; - options: RuntimeSkillOption[]; - optionsError: string | null; -} - -interface RuntimeSkillCronListProps { - loading: boolean; - skills: CronSkillConfig[]; - draftValues: Record; - savingKey: string | null; - onSetDraftValues: (updater: (prev: Record) => Record) => void; - onSaveOptionValue: (skillId: string, option: RuntimeSkillOption, rawValue: string) => void; - onToggleBooleanOption: (skillId: string, option: RuntimeSkillOption) => void; -} - -const RuntimeSkillCronList = ({ - loading, - skills, - draftValues, - savingKey, - onSetDraftValues, - onSaveOptionValue, - onToggleBooleanOption, -}: RuntimeSkillCronListProps) => { - const hasAnyRuntimeCronConfig = skills.length > 0; - - return ( -
-
-

Runtime Skill Cron Settings

-

- Skill-level cron and interval options from the runtime. -

-
- - {loading && ( -
Loading runtime cron settings...
- )} - - {!loading && !hasAnyRuntimeCronConfig && ( -
- No cron-capable skills were found in the current runtime. -
- )} - - {!loading && - skills.map((skill, skillIndex) => ( -
-
-
-
{skill.name}
-
{skill.skillId}
-
- - {skill.enabled ? 'Enabled' : 'Disabled'} - -
- - {skill.manifestTickInterval !== null && ( -
- Manifest tick interval:{' '} - {skill.manifestTickInterval}s -
- )} - - {skill.optionsError && ( -
- Could not load runtime options: {skill.optionsError} -
- )} - - {skill.options.length > 0 && ( -
- {skill.options.map(option => { - const optionKey = `${skill.skillId}:${option.name}`; - const draft = draftValues[optionKey] ?? ''; - const busy = savingKey === optionKey; - - return ( -
-
-
{option.label}
- {option.description && ( -
- {option.description} -
- )} -
- - {option.type === 'boolean' && ( - - )} - - {option.type === 'select' && option.options && ( -
- -
- )} - - {(option.type === 'text' || option.type === 'number') && ( -
- - onSetDraftValues(prev => ({ - ...prev, - [optionKey]: event.target.value, - })) - } - className="input input-bordered w-full text-slate-900 bg-white" - placeholder={option.type === 'number' ? '60' : '*/5 * * * *'} - /> - -
- )} -
- ); - })} -
- )} -
- ))} -
- ); -}; - -export default RuntimeSkillCronList; diff --git a/app/src/components/skills/AuthModeSelector.tsx b/app/src/components/skills/AuthModeSelector.tsx deleted file mode 100644 index a4e6ebdf3..000000000 --- a/app/src/components/skills/AuthModeSelector.tsx +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Card-based selector for skill authentication modes. - * Displays available auth modes (managed, self_hosted, text) as clickable cards. - * For managed mode, clicking immediately triggers the OAuth flow. - */ - -import type { ReactElement } from "react"; -import type { AuthMode } from "../../lib/skills/types.ts"; - -interface AuthModeSelectorProps { - modes: AuthMode[]; - onSelect: (mode: AuthMode) => void; - disabled?: boolean; -} - -const MODE_ICONS: Record ReactElement> = { - managed: ({ className }) => ( - - - - ), - self_hosted: ({ className }) => ( - - - - ), - text: ({ className }) => ( - - - - ), -}; - -const DEFAULT_LABELS: Record = { - managed: "OpenHuman Managed", - self_hosted: "Self-hosted", - text: "Credential Text", -}; - -const DEFAULT_DESCRIPTIONS: Record = { - managed: "One-click setup through OpenHuman", - self_hosted: "Enter your own API credentials", - text: "Paste credential content directly", -}; - -function formatProviderName(provider: string): string { - const names: Record = { - notion: "Notion", - google: "Google", - github: "GitHub", - slack: "Slack", - discord: "Discord", - twitter: "Twitter", - linear: "Linear", - gitlab: "GitLab", - }; - return names[provider] ?? provider.charAt(0).toUpperCase() + provider.slice(1); -} - -export default function AuthModeSelector({ - modes, - onSelect, - disabled, -}: AuthModeSelectorProps) { - return ( -
-
-

- Choose how to connect -

-

- Select an authentication method -

-
- - {modes.map((mode) => { - const IconComponent = MODE_ICONS[mode.type] ?? MODE_ICONS.self_hosted; - const label = - mode.type === "managed" && mode.provider - ? mode.label ?? `Connect with ${formatProviderName(mode.provider)}` - : mode.label ?? DEFAULT_LABELS[mode.type] ?? mode.type; - const description = - mode.description ?? DEFAULT_DESCRIPTIONS[mode.type] ?? ""; - - return ( - - ); - })} -
- ); -} diff --git a/app/src/components/skills/SetupFormRenderer.tsx b/app/src/components/skills/SetupFormRenderer.tsx deleted file mode 100644 index f9624fe38..000000000 --- a/app/src/components/skills/SetupFormRenderer.tsx +++ /dev/null @@ -1,269 +0,0 @@ -/** - * Dynamic form renderer for skill setup steps. - * Takes a SetupStep and renders appropriate form fields. - */ - -import { useState } from "react"; -import type { SetupStep, SetupFieldError } from "../../lib/skills/types"; - -interface SetupFormRendererProps { - step: SetupStep; - errors?: SetupFieldError[] | null; - loading?: boolean; - onSubmit: (values: Record) => void; - onCancel: () => void; -} - -export default function SetupFormRenderer({ - step, - errors, - loading, - onSubmit, - onCancel, -}: SetupFormRendererProps) { - const [values, setValues] = useState>(() => { - const defaults: Record = {}; - for (const field of step.fields) { - if (field.default !== undefined && field.default !== null) { - defaults[field.name] = field.default; - } else if (field.type === "boolean") { - defaults[field.name] = false; - } else { - defaults[field.name] = ""; - } - } - return defaults; - }); - - const [showPasswords, setShowPasswords] = useState>( - {}, - ); - - const getFieldError = (fieldName: string): string | undefined => { - return errors?.find((e) => e.field === fieldName)?.message; - }; - - const getGeneralError = (): string | undefined => { - return errors?.find((e) => e.field === "")?.message; - }; - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - onSubmit(values); - }; - - const updateValue = (name: string, value: unknown) => { - setValues((prev) => ({ ...prev, [name]: value })); - }; - - return ( -
- {/* Step header */} -
-

{step.title}

- {step.description && ( -

{step.description}

- )} -
- - {/* General error */} - {getGeneralError() && ( -
-

{getGeneralError()}

-
- )} - - {/* Form fields */} - {step.fields.map((field) => { - const fieldError = getFieldError(field.name); - const value = values[field.name]; - - return ( -
- - - {field.description && ( -

{field.description}

- )} - - {/* Text / Number input */} - {(field.type === "text" || field.type === "number") && ( - - updateValue( - field.name, - field.type === "number" - ? Number(e.target.value) - : e.target.value, - ) - } - placeholder={field.placeholder ?? undefined} - disabled={loading} - className={`w-full px-3 py-2.5 bg-stone-50 border rounded-xl text-sm text-stone-900 placeholder-stone-400 focus:outline-none focus:ring-1 transition-colors ${ - fieldError - ? "border-coral-500/50 focus:ring-coral-500/30" - : "border-stone-200 focus:ring-primary-500/30 focus:border-primary-500/50" - }`} - /> - )} - - {/* Password input */} - {field.type === "password" && ( -
- updateValue(field.name, e.target.value)} - placeholder={field.placeholder ?? undefined} - disabled={loading} - className={`w-full px-3 py-2.5 pr-10 bg-stone-50 border rounded-xl text-sm text-stone-900 placeholder-stone-400 focus:outline-none focus:ring-1 transition-colors ${ - fieldError - ? "border-coral-500/50 focus:ring-coral-500/30" - : "border-stone-200 focus:ring-primary-500/30 focus:border-primary-500/50" - }`} - /> - -
- )} - - {/* Select dropdown */} - {field.type === "select" && ( - - )} - - {/* Textarea */} - {field.type === "textarea" && ( -