"use client"; import { useState } from "react"; import { IconCode } from "@tabler/icons-react"; import { Card, CardContent, CardHeader, CardTitle } from "@kandev/ui/card"; import { Button } from "@kandev/ui/button"; import { Input } from "@kandev/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@kandev/ui/select"; import { SettingsSection } from "@/components/settings/settings-section"; import { useAppStore, useAppStoreApi } from "@/components/state-provider"; import { useShellSettings } from "@/hooks/domains/settings/use-shell-settings"; import { updateUserSettings } from "@/lib/api"; import { useRequest } from "@/lib/http/use-request"; const AUTO_SHELL = "auto"; const CUSTOM_SHELL = "custom"; type ShellOption = { value: string; label: string }; function resolveShellSelection(preferredShell: string, shellOptions: ShellOption[]) { if (!preferredShell) { return { selection: AUTO_SHELL, customShell: "" }; } if (shellOptions.some((option) => option.value === preferredShell)) { return { selection: preferredShell, customShell: "" }; } return { selection: CUSTOM_SHELL, customShell: preferredShell }; } type ShellSelectProps = { shellSelection: string; onSelectionChange: (value: string) => void; customShell: string; onCustomShellChange: (value: string) => void; shellLoaded: boolean; shellOptions: ShellOption[]; }; function ShellSelect({ shellSelection, onSelectionChange, customShell, onCustomShellChange, shellLoaded, shellOptions, }: ShellSelectProps) { return ( <>
{shellSelection === CUSTOM_SHELL && (
onCustomShellChange(event.target.value)} placeholder="/bin/zsh" />

Enter a shell path or command available in the agent environment.

)} ); } export function ShellSettingsCard() { const setUserSettings = useAppStore((state) => state.setUserSettings); const storeApi = useAppStoreApi(); const shellSettings = useShellSettings(); const initialShellValue = shellSettings.preferredShell ?? ""; const initialShellOptions = shellSettings.shellOptions ?? []; const initialSelection = resolveShellSelection(initialShellValue, initialShellOptions); const [preferredShell, setPreferredShell] = useState(initialShellValue); const [baselineShell, setBaselineShell] = useState(initialShellValue); const [shellSelection, setShellSelection] = useState(initialSelection.selection); const [customShell, setCustomShell] = useState(initialSelection.customShell); const [shellLoaded] = useState(shellSettings.loaded); const [shellOptions] = useState(initialShellOptions); const saveShellRequest = useRequest(async () => { const trimmed = preferredShell.trim(); const currentSettings = storeApi.getState().userSettings; await updateUserSettings({ workspace_id: currentSettings.workspaceId ?? "", repository_ids: currentSettings.repositoryIds, preferred_shell: trimmed, }); setBaselineShell(trimmed); setUserSettings({ ...currentSettings, preferredShell: trimmed || null, loaded: true, }); }); // Store data is SSR-hydrated for settings. Local state is initialized once. const shellDirty = preferredShell.trim() !== baselineShell.trim(); return ( } title="Shell" description="Pick the default shell for task sessions" > Preferred Shell { setShellSelection(value); if (value === AUTO_SHELL) { setPreferredShell(""); setCustomShell(""); return; } if (value === CUSTOM_SHELL) { setPreferredShell(customShell); return; } setPreferredShell(value); setCustomShell(""); }} customShell={customShell} onCustomShellChange={(value) => { setCustomShell(value); setPreferredShell(value); }} shellLoaded={shellLoaded} shellOptions={shellOptions} />

New task sessions will use this shell. Existing sessions keep their current shell.

); }