UNPKG

capsule-ai-cli

Version:

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

127 lines 5.22 kB
import { TerminalController } from './terminal-controller.js'; export class LayoutManager { minMessageHeight = 3; baseFooterHeight = 6; calculateLayout(options) { const { columns: terminalWidth, rows: terminalHeight } = TerminalController.getSize(); let suggestionHeight = 0; let minMessageHeight = this.minMessageHeight; if (options.showingSuggestions && options.suggestionCount > 0) { if (options.isSlashCommand) { minMessageHeight = 1; const minOtherHeight = this.baseFooterHeight + minMessageHeight; const availableForSuggestions = Math.max(0, terminalHeight - minOtherHeight); suggestionHeight = Math.min(options.suggestionCount, availableForSuggestions); } else { const minOtherHeight = 10; const availableRows = Math.max(0, terminalHeight - minOtherHeight); suggestionHeight = Math.min(options.suggestionCount, Math.max(3, Math.floor(availableRows * 0.6))); } } let inputHeight = options.inputLineCount || 1; const maxInputHeight = this.calculateMaxInputHeight(terminalHeight, suggestionHeight, minMessageHeight); if (inputHeight > maxInputHeight) { inputHeight = maxInputHeight; } let footerHeight = this.baseFooterHeight + inputHeight - 1; if (suggestionHeight > 0) { footerHeight += suggestionHeight + 1; } const messageAreaHeight = Math.max(minMessageHeight, terminalHeight - footerHeight); const animationRow = messageAreaHeight + 1; const inputTopRow = animationRow + 1; const inputContentRow = inputTopRow + 1; const inputBottomRow = inputContentRow + inputHeight; const suggestionStartRow = inputBottomRow + 2; let footerRow = suggestionStartRow; if (suggestionHeight > 0) { footerRow = suggestionStartRow + suggestionHeight + 1; } footerRow = Math.min(footerRow, terminalHeight - 1); return { terminalWidth, terminalHeight, messageAreaHeight, footerHeight, inputHeight, suggestionHeight, animationRow, inputTopRow, inputContentRow, inputBottomRow, suggestionStartRow, footerRow }; } calculateMaxInputHeight(terminalHeight, suggestionHeight, minMessageHeight) { const fixedComponents = 5; const reservedHeight = fixedComponents + suggestionHeight + minMessageHeight; const availableForInput = terminalHeight - reservedHeight; return Math.max(1, availableForInput); } isLayoutValid(layout) { return (layout.messageAreaHeight >= 1 && layout.footerRow < layout.terminalHeight && layout.inputHeight >= 1); } calculateVisibleRange(totalLines, messageAreaHeight, scrollPosition) { const maxStartIdx = Math.max(0, totalLines - messageAreaHeight); const startIdx = Math.max(0, Math.min(maxStartIdx - scrollPosition, maxStartIdx)); const endIdx = Math.min(startIdx + messageAreaHeight, totalLines); return { start: startIdx, end: endIdx }; } calculateCursorPosition(inputContentRow, inputHeight, currentLineLength, terminalHeight, terminalWidth) { const cursorRow = Math.min(inputContentRow + inputHeight - 1, terminalHeight - 1); const cursorCol = Math.min(3 + currentLineLength, terminalWidth); return { row: cursorRow, col: cursorCol }; } canFitSuggestions(terminalHeight, currentFooterHeight, suggestionCount) { const availableSpace = terminalHeight - currentFooterHeight - this.minMessageHeight; return availableSpace >= Math.min(3, suggestionCount); } calculateFooterLayout(terminalWidth) { const minPadding = 2; const separatorSpace = 3; const totalContentWidth = terminalWidth - minPadding; const maxLeftContentWidth = Math.floor(totalContentWidth * 0.6); const maxRightContentWidth = Math.floor(totalContentWidth * 0.4) - separatorSpace; return { maxLeftContentWidth, maxRightContentWidth, paddingSpace: minPadding }; } getLayoutMode(terminalWidth, terminalHeight) { if (terminalWidth < 80 || terminalHeight < 24) { return 'compact'; } else if (terminalWidth >= 120 && terminalHeight >= 40) { return 'spacious'; } return 'normal'; } adjustForLayoutMode(layout, mode) { const adjusted = { ...layout }; switch (mode) { case 'compact': if (adjusted.suggestionHeight > 3) { adjusted.suggestionHeight = 3; } break; case 'spacious': break; default: break; } return adjusted; } } export const layoutManager = new LayoutManager(); //# sourceMappingURL=layout-manager.js.map