UNPKG

pyb-ts

Version:

PYB-CLI - Minimal AI Agent with multi-model support and CLI interface

167 lines (166 loc) 7.6 kB
import { Box, Text, useInput } from "ink"; import * as React from "react"; import { useState } from "react"; import figures from "figures"; import { getTheme } from "@utils/theme"; import { saveGlobalConfig, getGlobalConfig } from "@utils/config"; import { useExitOnCtrlCD } from "@hooks/useExitOnCtrlCD"; import { getModelManager } from "@utils/model"; function Config({ onClose }) { const [globalConfig, setGlobalConfig] = useState(getGlobalConfig()); const initialConfig = React.useRef(getGlobalConfig()); const [selectedIndex, setSelectedIndex] = useState(0); const exitState = useExitOnCtrlCD(() => process.exit(0)); const [editingString, setEditingString] = useState(false); const [currentInput, setCurrentInput] = useState(""); const [inputError, setInputError] = useState(null); const modelManager = getModelManager(); const activeProfiles = modelManager.getAvailableModels(); const settings = [ // Global settings { id: "theme", label: "Theme", value: globalConfig.theme ?? "dark", options: ["dark", "light"], onChange(theme2) { const config = { ...getGlobalConfig(), theme: theme2 }; saveGlobalConfig(config); setGlobalConfig(config); }, type: "enum" }, { id: "verbose", label: "Verbose mode", value: globalConfig.verbose ?? false, onChange(verbose) { const config = { ...getGlobalConfig(), verbose }; saveGlobalConfig(config); setGlobalConfig(config); }, type: "boolean" }, { id: "stream", label: "Stream responses", value: globalConfig.stream ?? true, onChange(stream) { const config = { ...getGlobalConfig(), stream }; saveGlobalConfig(config); setGlobalConfig(config); }, type: "boolean" } ]; const theme = getTheme(); useInput((input, key) => { if (editingString) { if (key.return) { const currentSetting = settings[selectedIndex]; if (currentSetting?.type === "string") { try { currentSetting.onChange(currentInput); setEditingString(false); setCurrentInput(""); setInputError(null); } catch (error) { setInputError( error instanceof Error ? error.message : "Invalid input" ); } } else if (currentSetting?.type === "number") { const numValue = parseFloat(currentInput); if (isNaN(numValue)) { setInputError("Please enter a valid number"); } else { try { ; currentSetting.onChange(numValue); setEditingString(false); setCurrentInput(""); setInputError(null); } catch (error) { setInputError( error instanceof Error ? error.message : "Invalid input" ); } } } } else if (key.escape) { setEditingString(false); setCurrentInput(""); setInputError(null); } else if (key.delete || key.backspace) { setCurrentInput((prev) => prev.slice(0, -1)); } else if (input) { setCurrentInput((prev) => prev + input); } return; } if (key.upArrow && !exitState.pending) { setSelectedIndex((prev) => Math.max(0, prev - 1)); } else if (key.downArrow && !exitState.pending) { setSelectedIndex((prev) => Math.min(settings.length - 1, prev + 1)); } else if (key.return && !exitState.pending) { const currentSetting = settings[selectedIndex]; if (currentSetting?.disabled) return; if (currentSetting?.type === "boolean") { currentSetting.onChange(!currentSetting.value); } else if (currentSetting?.type === "enum") { const currentIndex = currentSetting.options.indexOf( currentSetting.value ); const nextIndex = (currentIndex + 1) % currentSetting.options.length; currentSetting.onChange(currentSetting.options[nextIndex]); } else if (currentSetting?.type === "string" || currentSetting?.type === "number") { setCurrentInput(String(currentSetting.value)); setEditingString(true); setInputError(null); } } else if (key.escape && !exitState.pending) { const currentConfigString = JSON.stringify(getGlobalConfig()); const initialConfigString = JSON.stringify(initialConfig.current); if (currentConfigString !== initialConfigString) { saveGlobalConfig(getGlobalConfig()); } onClose(); } }); return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React.createElement( Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.secondaryBorder, paddingX: 2, paddingY: 1, gap: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true }, "Configuration", " ", exitState.pending ? `(press ${exitState.keyName} again to exit)` : ""), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.success }, "Model Configuration:"), activeProfiles.length === 0 ? /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, "No models configured. Use /model to add models.") : /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: 2 }, activeProfiles.map((profile) => /* @__PURE__ */ React.createElement(React.Fragment, { key: profile.modelName }, /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, "\uFFFD\uFFFD?", profile.name, " (", profile.provider, ")"))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: theme.suggestion }, "Use /model to manage model configurations")))), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, settings.map((setting, index) => /* @__PURE__ */ React.createElement(Box, { key: setting.id, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React.createElement( Text, { color: index === selectedIndex ? theme.success : setting.disabled ? theme.secondaryText : theme.text }, index === selectedIndex ? figures.pointer : " ", " ", setting.label ), /* @__PURE__ */ React.createElement( Text, { color: setting.disabled ? theme.secondaryText : theme.suggestion }, setting.type === "boolean" ? setting.value ? "enabled" : "disabled" : setting.type === "enum" ? setting.value : String(setting.value) )), index === selectedIndex && editingString && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.suggestion }, "Enter new value: ", currentInput), inputError && /* @__PURE__ */ React.createElement(Text, { color: "red" }, inputError))))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, editingString ? "Enter to save \xB7 Esc to cancel" : /* @__PURE__ */ React.createElement(React.Fragment, null, "\uFFFD\uFFFD?\uFFFD\uFFFD?to navigate \xB7 Enter to change \xB7 Esc to close", /* @__PURE__ */ React.createElement(Text, { color: theme.suggestion }, " ", "\xB7 Use /model for model config")))) )); } export { Config }; //# sourceMappingURL=Config.js.map