openai-cli-unofficial
Version:
A powerful OpenAI CLI Coding Agent built with TypeScript
124 lines • 4.98 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InteractiveMenu = exports.GeminiStyleMenu = void 0;
const prompts_1 = require("@inquirer/prompts");
const chalk_1 = __importDefault(require("chalk"));
class GeminiStyleMenu {
static async show(options) {
// 使用新的@inquirer/prompts的select
const choices = options.choices.map(choice => ({
name: this.formatChoice(choice, false),
value: choice.value,
description: choice.description
}));
const result = await (0, prompts_1.select)({
message: options.message,
choices
});
return result;
}
static formatChoice(choice, isSelected) {
const circle = isSelected ? '●' : '○';
const textColor = isSelected ? chalk_1.default.cyan : chalk_1.default.white;
const circleColor = isSelected ? chalk_1.default.cyan : chalk_1.default.gray;
let formatted = `${circleColor(circle)} ${textColor(choice.name)}`;
if (choice.description) {
formatted += chalk_1.default.gray(` - ${choice.description}`);
}
return formatted;
}
}
exports.GeminiStyleMenu = GeminiStyleMenu;
// 扩展inquirer的样式
class InteractiveMenu {
static async show(options) {
console.log(chalk_1.default.white(options.message));
console.log();
let selectedIndex = 0;
const choices = options.choices;
let isFirstRender = true;
const renderMenu = () => {
return choices.map((choice, index) => {
const isSelected = index === selectedIndex;
const circle = isSelected ? chalk_1.default.cyan('●') : chalk_1.default.gray('○');
const text = isSelected ? chalk_1.default.cyan.bold(choice.name) : chalk_1.default.white(choice.name);
const description = choice.description
? (isSelected ? chalk_1.default.cyan(` ${choice.description}`) : chalk_1.default.gray(` ${choice.description}`))
: '';
return ` ${circle} ${text}${description}`;
});
};
const showMenu = () => {
if (!isFirstRender) {
// 隐藏光标,减少闪烁
process.stdout.write('\x1B[?25l');
// 移动到菜单开始位置
process.stdout.write('\x1B[' + choices.length + 'A');
// 清除从当前位置到屏幕末尾的内容
process.stdout.write('\x1B[0J');
}
// 批量渲染所有菜单项
const menuLines = renderMenu();
process.stdout.write(menuLines.join('\n') + '\n');
if (!isFirstRender) {
// 显示光标
process.stdout.write('\x1B[?25h');
}
isFirstRender = false;
};
return new Promise((resolve) => {
// 隐藏光标以减少闪烁
process.stdout.write('\x1B[?25l');
// 初始显示
showMenu();
const stdin = process.stdin;
if (stdin.isTTY) {
stdin.setRawMode(true);
}
stdin.resume();
stdin.setEncoding('utf8');
const cleanup = () => {
stdin.removeListener('data', keyHandler);
if (stdin.isTTY) {
try {
stdin.setRawMode(false);
}
catch (error) {
// 忽略错误
}
}
stdin.pause();
// 恢复光标显示
process.stdout.write('\x1B[?25h');
};
const keyHandler = (key) => {
switch (key) {
case '\u001B[A': // 上箭头
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : choices.length - 1;
showMenu();
break;
case '\u001B[B': // 下箭头
selectedIndex = selectedIndex < choices.length - 1 ? selectedIndex + 1 : 0;
showMenu();
break;
case '\r': // 回车
case '\n':
cleanup();
console.log();
resolve(choices[selectedIndex].value);
break;
case '\u0003': // Ctrl+C
cleanup();
process.exit();
break;
}
};
stdin.on('data', keyHandler);
});
}
}
exports.InteractiveMenu = InteractiveMenu;
//# sourceMappingURL=menu.js.map