UNPKG

capsule-ai-cli

Version:

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

179 lines 6.01 kB
import chalk from 'chalk'; import { TextProcessor } from './text-processor.js'; export class SuggestionEngine { commands = []; currentSuggestions = []; selectedIndex = 0; isShowing = false; setCommands(commands) { this.commands = commands; } updateSuggestions(input, minLength = 1) { if (!input || input.length < minLength) { this.clearSuggestions(); return; } const search = input.toLowerCase(); let matches = this.commands.filter(cmd => cmd.cmd.toLowerCase().startsWith(search)); matches = matches.sort((a, b) => a.cmd.localeCompare(b.cmd)); this.currentSuggestions = matches.map(match => ({ ...match, score: this.calculateMatchScore(match.cmd, search) })); if (this.currentSuggestions.length > 0) { this.isShowing = true; if (this.selectedIndex >= this.currentSuggestions.length) { this.selectedIndex = this.currentSuggestions.length - 1; } } else { this.clearSuggestions(); } } calculateMatchScore(cmd, search) { if (cmd.toLowerCase() === search) { return 100; } if (cmd.toLowerCase().startsWith(search)) { return 90 - (cmd.length - search.length); } const index = cmd.toLowerCase().indexOf(search); if (index > 0) { return 50 - index; } return 0; } clearSuggestions() { this.currentSuggestions = []; this.selectedIndex = 0; this.isShowing = false; } selectPrevious() { if (!this.isShowing || this.currentSuggestions.length === 0) { return false; } if (this.selectedIndex > 0) { this.selectedIndex--; return true; } return false; } selectNext() { if (!this.isShowing || this.currentSuggestions.length === 0) { return false; } if (this.selectedIndex < this.currentSuggestions.length - 1) { this.selectedIndex++; return true; } return false; } getSelectedSuggestion() { if (!this.isShowing || this.currentSuggestions.length === 0) { return null; } return this.currentSuggestions[this.selectedIndex]; } acceptSuggestion() { const selected = this.getSelectedSuggestion(); if (selected) { this.clearSuggestions(); return selected.cmd; } return null; } getCommonPrefix(input) { const matches = this.currentSuggestions; if (matches.length === 0) { return null; } if (matches.length === 1) { return matches[0].cmd; } let commonPrefix = matches[0].cmd; for (let i = 1; i < matches.length; i++) { const cmd = matches[i].cmd; let j = 0; while (j < commonPrefix.length && j < cmd.length && commonPrefix[j].toLowerCase() === cmd[j].toLowerCase()) { j++; } commonPrefix = commonPrefix.substring(0, j); } return commonPrefix.length > input.length ? commonPrefix : null; } renderSuggestions(maxSuggestions, terminalWidth, searchTerm) { const lines = []; const search = searchTerm.toLowerCase(); const suggestionsToShow = Math.min(maxSuggestions, this.currentSuggestions.length); for (let i = 0; i < suggestionsToShow; i++) { const suggestion = this.currentSuggestions[i]; const isSelected = i === this.selectedIndex; const cmd = suggestion.cmd; const desc = suggestion.desc; const matchIndex = cmd.toLowerCase().indexOf(search); let formattedCmd; if (matchIndex === 0) { const matchedPart = cmd.substring(0, search.length); const remainingPart = cmd.substring(search.length); if (isSelected) { formattedCmd = chalk.bold.yellow(matchedPart) + chalk.bold.cyan(remainingPart); } else { formattedCmd = chalk.yellow(matchedPart) + chalk.gray(remainingPart); } } else { formattedCmd = isSelected ? chalk.bold.cyan(cmd) : chalk.gray(cmd); } let line; if (isSelected) { line = chalk.cyan(' ▶ ') + formattedCmd + chalk.gray(' - ' + desc); } else { line = chalk.dim(' ') + formattedCmd + chalk.dim(' - ' + desc); } line = TextProcessor.fitText(line, terminalWidth); lines.push(line); } return lines; } getState() { return { isShowing: this.isShowing, suggestions: [...this.currentSuggestions], selectedIndex: this.selectedIndex, count: this.currentSuggestions.length }; } isShowingSuggestions() { return this.isShowing; } getSuggestionCount() { return this.currentSuggestions.length; } reset() { this.clearSuggestions(); } handleInputChange(input) { if (input.startsWith('/')) { this.updateSuggestions(input); } else { this.clearSuggestions(); } } calculateSuggestionHeight(availableSpace, preferredMin = 3) { if (!this.isShowing || this.currentSuggestions.length === 0) { return 0; } const count = this.currentSuggestions.length; if (count <= availableSpace) { return count; } return Math.min(count, Math.max(preferredMin, availableSpace)); } } export const suggestionEngine = new SuggestionEngine(); //# sourceMappingURL=suggestion-engine.js.map