/** * @license * Copyright 2025 Vybestack LLC * SPDX-License-Identifier: Apache-2.0 */ import React, { useState, useCallback, useMemo } from 'react'; import { Box, Text } from 'ink'; import { Colors } from '../../colors.js'; import { useKeypress } from '../../hooks/useKeypress.js'; import type { SubagentInfo } from './types.js'; interface ProfileInfo { name: string; provider?: string; model?: string; temperature?: number; maxTokens?: number; } interface ProfileAttachmentWizardProps { subagent: SubagentInfo; profiles: string[]; getProfileInfo?: (profileName: string) => Promise; onConfirm: (profileName: string) => Promise; onCancel: () => void; isFocused?: boolean; } function useProfilePreview( selectedProfile: string, getProfileInfo?: (profileName: string) => Promise, ) { const [previewInfo, setPreviewInfo] = useState(null); React.useEffect(() => { let cancelled = false; if (getProfileInfo && selectedProfile) { getProfileInfo(selectedProfile) .then((info) => { if (!cancelled) setPreviewInfo(info); }) .catch(() => { if (!cancelled) setPreviewInfo(null); }); } else { setPreviewInfo(null); } return () => { cancelled = true; }; }, [selectedProfile, getProfileInfo]); return previewInfo; } function ProfilePreview({ previewInfo, selectedProfile, }: { previewInfo: ProfileInfo | null; selectedProfile: string; }) { if (!previewInfo) return Profile: {selectedProfile}; return ( <> {previewInfo.provider && ( Provider: {previewInfo.provider} )} {previewInfo.model && ( Model: {previewInfo.model} )} {previewInfo.temperature !== undefined && ( Temperature: {previewInfo.temperature} )} {previewInfo.maxTokens !== undefined && ( Max Tokens: {previewInfo.maxTokens} )} ); } function ProfileList({ visibleProfiles, startIndex, selectedIndex, currentProfile, }: { visibleProfiles: string[]; startIndex: number; selectedIndex: number; currentProfile: string; }) { return ( {visibleProfiles.map((profile, idx) => { const actualIndex = startIndex + idx; const isSelected = actualIndex === selectedIndex; const isCurrent = profile === currentProfile; return ( {isSelected ? '→ ' : ' '} {profile} {isCurrent && (current)} ); })} ); } function EmptyProfilesMessage() { return ( No profiles available. Create a profile first. [ESC] Cancel ); } function ProfileAttachmentWizardView({ subagent, profiles, selectedProfile, previewInfo, startIndex, selectedIndex, endIndex, visibleProfiles, error, isConfirming, }: { subagent: SubagentInfo; profiles: string[]; selectedProfile: string; previewInfo: ProfileInfo | null; startIndex: number; selectedIndex: number; endIndex: number; visibleProfiles: string[]; error: string | null; isConfirming: boolean; }) { return ( Attach Profile to: {subagent.name} ────────────────────────────────────────────────────────── {error && ( {error} )} Profile Selection (showing {startIndex + 1}-{endIndex} of{' '} {profiles.length}): Selected Profile Preview: ────────────────────────────────────────────────────────── Controls: ↑↓ Navigate [Enter] Confirm [ESC] Cancel {isConfirming && ( Attaching profile... )} ); } function useProfileSelectionState(initialProfile: string, profiles: string[]) { const [selectedIndex, setSelectedIndex] = useState(() => { const idx = profiles.indexOf(initialProfile); return idx >= 0 ? idx : 0; }); const totalProfiles = profiles.length; const moveSelection = useCallback( (delta: number) => { setSelectedIndex((prev) => { let newIndex = prev + delta; if (newIndex < 0) newIndex = 0; if (newIndex >= totalProfiles) newIndex = totalProfiles - 1; return newIndex; }); }, [totalProfiles], ); return { selectedIndex, moveSelection }; } export const ProfileAttachmentWizard: React.FC< ProfileAttachmentWizardProps > = ({ subagent, profiles, getProfileInfo, onConfirm, onCancel, isFocused = true, }) => { const { selectedIndex, moveSelection } = useProfileSelectionState( subagent.profile, profiles, ); const [isConfirming, setIsConfirming] = useState(false); const [error, setError] = useState(null); const selectedProfile = profiles[selectedIndex] || ''; const previewInfo = useProfilePreview(selectedProfile, getProfileInfo); const handleConfirm = useCallback(async () => { if (!selectedProfile) return; setIsConfirming(true); setError(null); try { await onConfirm(selectedProfile); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to attach profile'); setIsConfirming(false); } }, [selectedProfile, onConfirm]); useKeypress( (key) => { if (isConfirming) return; if (key.name === 'escape') { onCancel(); return; } if (key.name === 'up') { moveSelection(-1); return; } if (key.name === 'down') { moveSelection(1); return; } if (key.name === 'return') { void handleConfirm(); } }, { isActive: isFocused && !isConfirming }, ); const maxVisible = 6; const startIndex = useMemo( () => Math.max(0, selectedIndex - Math.floor(maxVisible / 2)), [selectedIndex], ); const endIndex = Math.min(profiles.length, startIndex + maxVisible); const visibleProfiles = profiles.slice(startIndex, endIndex); if (profiles.length === 0) return ; return ( ); };