giga-code
Version:
A personal AI CLI assistant powered by Grok for local development.
173 lines • 8.34 kB
JavaScript
;
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;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConversationHistory = void 0;
const react_1 = __importStar(require("react"));
const ink_1 = require("ink");
const conversation_manager_1 = require("../../utils/conversation-manager");
const fuzzy_search_1 = require("../../utils/fuzzy-search");
function ConversationHistory({ isVisible, onClose, onSelectConversation }) {
const [conversations, setConversations] = (0, react_1.useState)([]);
const [filteredConversations, setFilteredConversations] = (0, react_1.useState)([]);
const [selectedIndex, setSelectedIndex] = (0, react_1.useState)(0);
const [searchQuery, setSearchQuery] = (0, react_1.useState)('');
const [isLoading, setIsLoading] = (0, react_1.useState)(true);
const conversationManager = conversation_manager_1.ConversationManager.getInstance();
// Load conversations on mount
(0, react_1.useEffect)(() => {
if (isVisible) {
loadConversations();
}
}, [isVisible]);
// Filter conversations when search query changes
(0, react_1.useEffect)(() => {
if (!searchQuery.trim()) {
setFilteredConversations(conversations);
}
else {
const filtered = (0, fuzzy_search_1.fuzzySearch)(searchQuery, conversations, (conv) => `${conv.title} ${conv.preview}`, 10);
setFilteredConversations(filtered);
}
setSelectedIndex(0);
}, [conversations, searchQuery]);
const loadConversations = async () => {
setIsLoading(true);
try {
const convList = await conversationManager.listConversations();
setConversations(convList);
}
catch (error) {
console.error('Failed to load conversations:', error);
}
finally {
setIsLoading(false);
}
};
const formatDate = (date) => {
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffDays === 0) {
return 'Today';
}
else if (diffDays === 1) {
return 'Yesterday';
}
else if (diffDays < 7) {
return `${diffDays}d ago`;
}
else if (diffDays < 30) {
return `${Math.floor(diffDays / 7)}w ago`;
}
else {
return date.toLocaleDateString();
}
};
const handleDeleteConversation = async (conversationId) => {
try {
await conversationManager.deleteConversation(conversationId);
await loadConversations();
}
catch (error) {
console.error('Failed to delete conversation:', error);
}
};
(0, ink_1.useInput)((input, key) => {
if (!isVisible)
return;
if (key.escape) {
onClose();
return;
}
if (key.return) {
if (filteredConversations.length > 0 && selectedIndex < filteredConversations.length) {
onSelectConversation(filteredConversations[selectedIndex].id);
onClose();
}
return;
}
if (key.upArrow) {
setSelectedIndex(prev => prev > 0 ? prev - 1 : Math.max(0, filteredConversations.length - 1));
return;
}
if (key.downArrow) {
setSelectedIndex(prev => prev < filteredConversations.length - 1 ? prev + 1 : 0);
return;
}
if (key.delete || key.backspace) {
if (searchQuery.length > 0) {
setSearchQuery(prev => prev.slice(0, -1));
}
return;
}
// Handle delete key (d) to delete conversation
if (input === 'd' && filteredConversations.length > 0) {
const conversation = filteredConversations[selectedIndex];
if (conversation) {
handleDeleteConversation(conversation.id);
}
return;
}
// Handle regular character input for search
if (input && input.length === 1 && !key.ctrl && !key.meta) {
setSearchQuery(prev => prev + input);
}
});
if (!isVisible) {
return null;
}
return (react_1.default.createElement(ink_1.Box, { flexDirection: "column", width: "100%", height: 20, borderStyle: "round", borderColor: "cyan", padding: 1 },
react_1.default.createElement(ink_1.Box, { marginBottom: 1 },
react_1.default.createElement(ink_1.Text, { bold: true, color: "cyan" }, "\uD83D\uDCDA Conversation History")),
react_1.default.createElement(ink_1.Box, { marginBottom: 1 },
react_1.default.createElement(ink_1.Text, { color: "gray" },
"Search: ",
searchQuery,
searchQuery && react_1.default.createElement(ink_1.Text, { color: "cyan" }, "\u2588"))),
isLoading ? (react_1.default.createElement(ink_1.Box, { justifyContent: "center", alignItems: "center", height: 10 },
react_1.default.createElement(ink_1.Text, { color: "cyan" }, "Loading conversations..."))) : filteredConversations.length === 0 ? (react_1.default.createElement(ink_1.Box, { justifyContent: "center", alignItems: "center", height: 10 },
react_1.default.createElement(ink_1.Text, { color: "gray" }, searchQuery ? 'No matching conversations found' : 'No conversations yet'))) : (react_1.default.createElement(ink_1.Box, { flexDirection: "column" }, filteredConversations.slice(0, 12).map((conversation, index) => {
const isSelected = index === selectedIndex;
return (react_1.default.createElement(ink_1.Box, { key: conversation.id, flexDirection: "column", width: "100%" },
react_1.default.createElement(ink_1.Box, { flexDirection: "row", justifyContent: "space-between" },
react_1.default.createElement(ink_1.Text, { color: isSelected ? 'cyan' : 'white', bold: isSelected },
isSelected ? '> ' : ' ',
conversation.title),
react_1.default.createElement(ink_1.Text, { color: isSelected ? 'cyan' : 'gray', dimColor: !isSelected }, formatDate(conversation.updatedAt))),
react_1.default.createElement(ink_1.Box, { flexDirection: "row", justifyContent: "space-between" },
react_1.default.createElement(ink_1.Text, { color: isSelected ? 'cyan' : 'gray', dimColor: !isSelected },
isSelected ? ' ' : ' ',
conversation.preview.slice(0, 50),
"..."),
react_1.default.createElement(ink_1.Text, { color: isSelected ? 'cyan' : 'gray', dimColor: !isSelected },
conversation.messageCount,
" msgs | ",
conversation.model))));
}))),
react_1.default.createElement(ink_1.Box, { marginTop: 1 },
react_1.default.createElement(ink_1.Text, { color: "gray", dimColor: true }, "\u2191\u2193 Navigate \u2022 Enter Select \u2022 d Delete \u2022 Esc Close \u2022 Type to search"))));
}
exports.ConversationHistory = ConversationHistory;
//# sourceMappingURL=conversation-history.js.map