import chalk from 'chalk'; import figures from 'figures'; import * as React from 'react'; import { useEffect, useState } from 'react'; import { Text } from '@anthropic/ink'; import { useKeybinding } from '../keybindings/useKeybinding.js'; import { toError } from '../utils/errors.js'; import { logError } from '../utils/log.js'; import { getSettingSourceName, type SettingSource } from '../utils/settings/constants.js'; import { updateSettingsForSource } from '../utils/settings/settings.js'; import { getEnvironmentSelectionInfo } from '../utils/teleport/environmentSelection.js'; import type { EnvironmentResource } from '../utils/teleport/environments.js'; import { ConfigurableShortcutHint } from './ConfigurableShortcutHint.js'; import { Select } from './CustomSelect/select.js'; import { Byline, Dialog, KeyboardShortcutHint, LoadingState } from '@anthropic/ink'; const DIALOG_TITLE = 'Select Remote Environment'; const SETUP_HINT = `Configure environments at: https://claude.ai/code`; type Props = { onDone: (message?: string) => void; }; type LoadingState = 'loading' | 'updating' | null; export function RemoteEnvironmentDialog({ onDone }: Props): React.ReactNode { const [loadingState, setLoadingState] = useState('loading'); const [environments, setEnvironments] = useState([]); const [selectedEnvironment, setSelectedEnvironment] = useState(null); const [selectedEnvironmentSource, setSelectedEnvironmentSource] = useState(null); const [error, setError] = useState(null); useEffect(() => { let cancelled = false; async function fetchInfo(): Promise { try { const result = await getEnvironmentSelectionInfo(); if (cancelled) return; setEnvironments(result.availableEnvironments); setSelectedEnvironment(result.selectedEnvironment); setSelectedEnvironmentSource(result.selectedEnvironmentSource); setLoadingState(null); } catch (err) { if (cancelled) return; const fetchError = toError(err); logError(fetchError); setError(fetchError.message); setLoadingState(null); } } void fetchInfo(); return () => { cancelled = true; }; }, []); function handleSelect(value: string): void { if (value === 'cancel') { onDone(); return; } setLoadingState('updating'); const selectedEnv = environments.find(env => env.environment_id === value); if (!selectedEnv) { onDone('Error: Selected environment not found'); return; } updateSettingsForSource('localSettings', { remote: { defaultEnvironmentId: selectedEnv.environment_id, }, }); onDone(`Set default remote environment to ${chalk.bold(selectedEnv.name)} (${selectedEnv.environment_id})`); } // Loading state if (loadingState === 'loading') { return ( ); } // Error state if (error) { return ( Error: {error} ); } // No environments available if (!selectedEnvironment) { return ( No remote environments available. ); } // Single environment - just show info if (environments.length === 1) { return ; } // Multiple environments - show selection UI return ( ); } function EnvironmentLabel({ environment }: { environment: EnvironmentResource }): React.ReactNode { return ( {figures.tick} Using {environment.name} ({environment.environment_id}) ); } function SingleEnvironmentContent({ environment, onDone, }: { environment: EnvironmentResource; onDone: () => void; }): React.ReactNode { // Handle Enter to continue useKeybinding('confirm:yes', onDone, { context: 'Confirmation' }); return ( ); } function MultipleEnvironmentsContent({ environments, selectedEnvironment, selectedEnvironmentSource, loadingState, onSelect, onCancel, }: { environments: EnvironmentResource[]; selectedEnvironment: EnvironmentResource; selectedEnvironmentSource: SettingSource | null; loadingState: LoadingState; onSelect: (value: string) => void; onCancel: () => void; }): React.ReactNode { const sourceSuffix = selectedEnvironmentSource && selectedEnvironmentSource !== 'localSettings' ? ` (from ${getSettingSourceName(selectedEnvironmentSource)} settings)` : ''; const subtitle = ( Currently using: {selectedEnvironment.name} {sourceSuffix} ); return ( {SETUP_HINT} {loadingState === 'updating' ? ( ) : (