@vibe-kit/grok-cli
Version:
An open-source AI agent that brings the power of Grok directly into your terminal.
183 lines • 10.2 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importStar(require("react"));
const ink_1 = require("ink");
const use_input_handler_1 = require("../../hooks/use-input-handler");
const loading_spinner_1 = require("./loading-spinner");
const command_suggestions_1 = require("./command-suggestions");
const model_selection_1 = require("./model-selection");
const chat_history_1 = require("./chat-history");
const chat_input_1 = require("./chat-input");
const mcp_status_1 = require("./mcp-status");
const confirmation_dialog_1 = __importDefault(require("./confirmation-dialog"));
const confirmation_service_1 = require("../../utils/confirmation-service");
const api_key_input_1 = __importDefault(require("./api-key-input"));
const cfonts_1 = __importDefault(require("cfonts"));
// Main chat component that handles input when agent is available
function ChatInterfaceWithAgent({ agent }) {
const [chatHistory, setChatHistory] = (0, react_1.useState)([]);
const [isProcessing, setIsProcessing] = (0, react_1.useState)(false);
const [processingTime, setProcessingTime] = (0, react_1.useState)(0);
const [tokenCount, setTokenCount] = (0, react_1.useState)(0);
const [isStreaming, setIsStreaming] = (0, react_1.useState)(false);
const [confirmationOptions, setConfirmationOptions] = (0, react_1.useState)(null);
const scrollRef = (0, react_1.useRef)();
const processingStartTime = (0, react_1.useRef)(0);
const confirmationService = confirmation_service_1.ConfirmationService.getInstance();
const { input, showCommandSuggestions, selectedCommandIndex, showModelSelection, selectedModelIndex, commandSuggestions, availableModels, autoEditEnabled, } = (0, use_input_handler_1.useInputHandler)({
agent,
chatHistory,
setChatHistory,
setIsProcessing,
setIsStreaming,
setTokenCount,
setProcessingTime,
processingStartTime,
isProcessing,
isStreaming,
isConfirmationActive: !!confirmationOptions,
});
(0, react_1.useEffect)(() => {
// Only clear console on non-Windows platforms or if not PowerShell
// Windows PowerShell can have issues with console.clear() causing flickering
const isWindows = process.platform === "win32";
const isPowerShell = process.env.ComSpec?.toLowerCase().includes("powershell") ||
process.env.PSModulePath !== undefined;
if (!isWindows || !isPowerShell) {
console.clear();
}
// Add top padding
console.log(" ");
// Generate logo with margin to match Ink paddingX={2}
const logoOutput = cfonts_1.default.render("GROK", {
font: "3d",
align: "left",
colors: ["magenta", "gray"],
space: true,
maxLength: "0",
gradient: ["magenta", "cyan"],
independentGradient: false,
transitionGradient: true,
env: "node",
});
// Add horizontal margin (2 spaces) to match Ink paddingX={2}
const logoLines = logoOutput.string.split("\n");
logoLines.forEach((line) => {
if (line.trim()) {
console.log(" " + line); // Add 2 spaces for horizontal margin
}
else {
console.log(line); // Keep empty lines as-is
}
});
console.log(" "); // Spacing after logo
setChatHistory([]);
}, []);
(0, react_1.useEffect)(() => {
const handleConfirmationRequest = (options) => {
setConfirmationOptions(options);
};
confirmationService.on("confirmation-requested", handleConfirmationRequest);
return () => {
confirmationService.off("confirmation-requested", handleConfirmationRequest);
};
}, [confirmationService]);
(0, react_1.useEffect)(() => {
if (!isProcessing && !isStreaming) {
setProcessingTime(0);
return;
}
if (processingStartTime.current === 0) {
processingStartTime.current = Date.now();
}
const interval = setInterval(() => {
setProcessingTime(Math.floor((Date.now() - processingStartTime.current) / 1000));
}, 1000);
return () => clearInterval(interval);
}, [isProcessing, isStreaming]);
const handleConfirmation = (dontAskAgain) => {
confirmationService.confirmOperation(true, dontAskAgain);
setConfirmationOptions(null);
};
const handleRejection = (feedback) => {
confirmationService.rejectOperation(feedback);
setConfirmationOptions(null);
// Reset processing states when operation is cancelled
setIsProcessing(false);
setIsStreaming(false);
setTokenCount(0);
setProcessingTime(0);
processingStartTime.current = 0;
};
return (react_1.default.createElement(ink_1.Box, { flexDirection: "column", paddingX: 2 },
chatHistory.length === 0 && !confirmationOptions && (react_1.default.createElement(ink_1.Box, { flexDirection: "column", marginBottom: 2 },
react_1.default.createElement(ink_1.Text, { color: "cyan", bold: true }, "Tips for getting started:"),
react_1.default.createElement(ink_1.Box, { marginTop: 1, flexDirection: "column" },
react_1.default.createElement(ink_1.Text, { color: "gray" }, "1. Ask questions, edit files, or run commands."),
react_1.default.createElement(ink_1.Text, { color: "gray" }, "2. Be specific for the best results."),
react_1.default.createElement(ink_1.Text, { color: "gray" }, "3. Create GROK.md files to customize your interactions with Grok."),
react_1.default.createElement(ink_1.Text, { color: "gray" }, "4. Press Shift+Tab to toggle auto-edit mode."),
react_1.default.createElement(ink_1.Text, { color: "gray" }, "5. /help for more information.")))),
react_1.default.createElement(ink_1.Box, { flexDirection: "column", marginBottom: 1 },
react_1.default.createElement(ink_1.Text, { dimColor: true }, "Type your request in natural language. Type 'exit' or Ctrl+C to quit.")),
react_1.default.createElement(ink_1.Box, { flexDirection: "column", ref: scrollRef },
react_1.default.createElement(chat_history_1.ChatHistory, { entries: chatHistory, isConfirmationActive: !!confirmationOptions })),
confirmationOptions && (react_1.default.createElement(confirmation_dialog_1.default, { operation: confirmationOptions.operation, filename: confirmationOptions.filename, showVSCodeOpen: confirmationOptions.showVSCodeOpen, content: confirmationOptions.content, onConfirm: handleConfirmation, onReject: handleRejection })),
!confirmationOptions && (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(loading_spinner_1.LoadingSpinner, { isActive: isProcessing || isStreaming, processingTime: processingTime, tokenCount: tokenCount }),
react_1.default.createElement(chat_input_1.ChatInput, { input: input, isProcessing: isProcessing, isStreaming: isStreaming }),
react_1.default.createElement(ink_1.Box, { flexDirection: "row" },
react_1.default.createElement(ink_1.Text, { color: "cyan" },
autoEditEnabled ? "▶" : "⏸",
" auto-edit:",
" ",
autoEditEnabled ? "on" : "off"),
react_1.default.createElement(ink_1.Box, { marginLeft: 1 },
react_1.default.createElement(ink_1.Text, { dimColor: true }, "(shift + tab)")),
react_1.default.createElement(ink_1.Box, { marginLeft: 2 },
react_1.default.createElement(ink_1.Text, { color: "yellow" },
"\u224B ",
agent.getCurrentModel())),
react_1.default.createElement(mcp_status_1.MCPStatus, null)),
react_1.default.createElement(command_suggestions_1.CommandSuggestions, { suggestions: commandSuggestions, input: input, selectedIndex: selectedCommandIndex, isVisible: showCommandSuggestions }),
react_1.default.createElement(model_selection_1.ModelSelection, { models: availableModels, selectedIndex: selectedModelIndex, isVisible: showModelSelection, currentModel: agent.getCurrentModel() })))));
}
// Main component that handles API key input or chat interface
function ChatInterface({ agent }) {
const [currentAgent, setCurrentAgent] = (0, react_1.useState)(agent || null);
const handleApiKeySet = (newAgent) => {
setCurrentAgent(newAgent);
};
if (!currentAgent) {
return react_1.default.createElement(api_key_input_1.default, { onApiKeySet: handleApiKeySet });
}
return react_1.default.createElement(ChatInterfaceWithAgent, { agent: currentAgent });
}
exports.default = ChatInterface;
//# sourceMappingURL=chat-interface.js.map