UNPKG

capsule-ai-cli

Version:

The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing

139 lines 6.46 kB
import React, { useState, useEffect, useRef } from 'react'; import { Box, Text, useInput } from 'ink'; import chalk from 'chalk'; import { getProviderColor } from '../utils/provider-colors.js'; export const InputBox = ({ value: controlledValue, onSubmit, onChange, onPasteStart, onPasteEnd, provider = 'openai' }) => { const [internalValue, setInternalValue] = useState(''); const [cursorPosition, setCursorPosition] = useState(0); const [showCursor, setShowCursor] = useState(true); const [pasteBuffer, setPasteBuffer] = useState(''); const [lastInputTime, setLastInputTime] = useState(0); const pasteTimeoutRef = useRef(null); const pastedContentRef = useRef({}); const value = controlledValue !== undefined ? controlledValue : internalValue; const providerColor = getProviderColor(provider); useEffect(() => { const timer = setInterval(() => { setShowCursor(prev => !prev); }, 500); return () => clearInterval(timer); }, []); useInput((input, key) => { if (input === '\\\r' || input === '\\' || input === '\\\n') { const newValue = value.slice(0, cursorPosition) + '\\' + value.slice(cursorPosition); handleChange(newValue); const lines = newValue.split('\\'); const currentLineIndex = newValue.substring(0, cursorPosition + 1).split('\\').length - 1; const isNewLine = currentLineIndex > 0 && lines[currentLineIndex] === ''; if (isNewLine) { setTimeout(() => setCursorPosition(cursorPosition + 1), 10); } else { setCursorPosition(cursorPosition + 1); } return; } if (key.return && !key.shift) { let finalValue = value; const summaryRegex = /\[Pasted text #\d+ \+\d+ lines\]/g; const summaries = value.match(summaryRegex); if (summaries) { summaries.forEach(summary => { const actualContent = pastedContentRef.current[summary]; if (actualContent) { finalValue = finalValue.replace(summary, actualContent); } }); } onSubmit(finalValue); handleChange(''); setCursorPosition(0); pastedContentRef.current = {}; return; } if (key.backspace || key.delete) { if (cursorPosition > 0) { const newValue = value.slice(0, cursorPosition - 1) + value.slice(cursorPosition); handleChange(newValue); setCursorPosition(cursorPosition - 1); } return; } if (key.leftArrow) { setCursorPosition(Math.max(0, cursorPosition - 1)); return; } if (key.rightArrow) { setCursorPosition(Math.min(value.length, cursorPosition + 1)); return; } if (input && input.length >= 1) { const now = Date.now(); const timeSinceLastInput = now - lastInputTime; setLastInputTime(now); const looksLikePaste = input.length > 10 || input.includes('\r') || (timeSinceLastInput < 50 && pasteBuffer.length > 0); if (looksLikePaste) { setPasteBuffer(prev => prev + input); if (pasteTimeoutRef.current) { clearTimeout(pasteTimeoutRef.current); } pasteTimeoutRef.current = setTimeout(() => { const fullPaste = pasteBuffer + input; const cleanedPaste = fullPaste.replace(/\r/g, '\n'); const lines = cleanedPaste.split('\n').filter(line => line.trim()); onPasteStart?.(); const lineCount = Math.max(lines.length, Math.ceil(cleanedPaste.length / 80)); const summary = `[Pasted text #1 +${lineCount} lines]`; pastedContentRef.current[summary] = cleanedPaste; const newValue = value.slice(0, cursorPosition) + summary + value.slice(cursorPosition); handleChange(newValue); setTimeout(() => { setCursorPosition(cursorPosition + summary.length); }, 100); setTimeout(() => onPasteEnd?.(), 100); setPasteBuffer(''); }, 50); return; } if (timeSinceLastInput > 100) { setPasteBuffer(''); } const newValue = value.slice(0, cursorPosition) + input + value.slice(cursorPosition); handleChange(newValue); const beforeCursor = value.substring(0, cursorPosition); const isStartOfLine = cursorPosition === 0 || beforeCursor.endsWith('\\'); if (isStartOfLine) { setTimeout(() => setCursorPosition(cursorPosition + input.length), 10); } else { setCursorPosition(cursorPosition + input.length); } } }, { isActive: true }); const handleChange = (newValue) => { if (controlledValue === undefined) { setInternalValue(newValue); } onChange?.(newValue); }; const lines = value.split('\\'); let remainingPos = cursorPosition; let cursorLine = 0; let cursorCol = 0; for (let i = 0; i < lines.length; i++) { if (remainingPos <= lines[i].length) { cursorLine = i; cursorCol = remainingPos; break; } remainingPos -= lines[i].length + 1; } return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: providerColor, paddingX: 1 }, lines.map((line, index) => (React.createElement(Box, { key: index }, React.createElement(Text, null, index === 0 ? chalk.hex(providerColor)('> ') : chalk.hex(providerColor)(' ')), index === cursorLine ? (React.createElement(Text, { color: providerColor }, line.substring(0, cursorCol), showCursor ? chalk.inverse(' ') : ' ', line.substring(cursorCol))) : (React.createElement(Text, { color: providerColor }, line)), index < lines.length - 1 && React.createElement(Text, null, chalk.gray('\\'))))))); }; //# sourceMappingURL=InputBox.js.map