Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 9 additions & 114 deletions src/cli.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import "dotenv/config";
import React, { useState, useEffect } from "react";
import { render, Box, Text, useApp, useInput } from "ink";

Check failure on line 3 in src/cli.tsx

View workflow job for this annotation

GitHub Actions / check

'useInput' is defined but never used. Allowed unused vars must match /^_/u
import type { XmtpEnv } from "@xmtp/agent-sdk";
import { privateKeyToAddress } from "viem/accounts";
import { Layout } from "./components/Layout.js";
import type { Command } from "./components/CommandPalette.js";
import { CommandSuggestion } from "./components/CommandSuggestions.js";
import { useXMTP } from "./hooks/useXMTP.js";
import { useKeyboard } from "./hooks/useKeyboard.js";
import { useStore } from "./store/state.js";

const RED = "#fc4c34";
const DIM_GREY = "#666666";
const LIGHT_GREY = "#888888";

Check failure on line 14 in src/cli.tsx

View workflow job for this annotation

GitHub Actions / check

'LIGHT_GREY' is assigned a value but never used. Allowed unused vars must match /^_/u

// ============================================================================
// Help Display
Expand Down Expand Up @@ -41,9 +42,8 @@
Ctrl+C Quit

COMMANDS:
/back Return to main conversation list
/list Toggle sidebar visibility
/chat <n> Switch to conversation number
/b Return to main conversation list
/c <n> Switch to conversation number
/new <address> Create new conversation with address
/refresh Refresh inbox and update conversations
/exit, /quit Exit application
Expand Down Expand Up @@ -90,92 +90,13 @@
const [errorTimeout, setErrorTimeout] = useState<NodeJS.Timeout | null>(null);
const [isInputActive, setIsInputActive] = useState(false);

// Command suggestions state
const [showSuggestions, setShowSuggestions] = useState(false);
const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState(0);


// Handle suggestion navigation
const handleSuggestionNavigation = (direction: 'up' | 'down') => {
if (!showSuggestions || suggestions.length === 0) return;

if (direction === 'up') {
setSelectedSuggestionIndex(prev =>
prev > 0 ? prev - 1 : suggestions.length - 1
);
} else {
setSelectedSuggestionIndex(prev =>
prev < suggestions.length - 1 ? prev + 1 : 0
);
}
};

// Handle suggestion selection
const handleSuggestionSelect = (suggestion: CommandSuggestion) => {
// Find the corresponding command
const command = commands.find(cmd => cmd.id === suggestion.id);
if (command) {
setInputValue(`/${command.name.toLowerCase().replace(/\s+/g, '-')}`);
setShowSuggestions(false);
setSelectedSuggestionIndex(0);
}
};

// Handle input change with suggestions
// Handle input change
const handleInputChange = (value: string) => {
setInputValue(value);

// Show suggestions when user types "/"
if (value.startsWith("/")) {
setShowSuggestions(true);
setSelectedSuggestionIndex(0);
} else {
setShowSuggestions(false);
setSelectedSuggestionIndex(0);
}
};

// Custom keyboard handler for suggestions
useInput((input, key) => {
if (!isInputActive || !showSuggestions) return;

// Handle arrow keys for suggestion navigation
if (key.upArrow) {
handleSuggestionNavigation('up');
return;
}

if (key.downArrow) {
handleSuggestionNavigation('down');
return;
}

// Handle tab for suggestion completion
if (key.tab && suggestions.length > 0) {
const selectedSuggestion = suggestions[selectedSuggestionIndex];
if (selectedSuggestion) {
handleSuggestionSelect(selectedSuggestion);
}
return;
}

// Handle enter to execute selected suggestion
if (key.return && suggestions.length > 0) {
const selectedSuggestion = suggestions[selectedSuggestionIndex];
if (selectedSuggestion) {
// Find the corresponding command and execute it
const command = commands.find(cmd => cmd.id === selectedSuggestion.id);
if (command) {
setInputValue(`/${command.name.toLowerCase().replace(/\s+/g, '-')}`);
setShowSuggestions(false);
setSelectedSuggestionIndex(0);
// Execute the command immediately
command.action();
}
}
return;
}
}, { isActive: isInputActive && showSuggestions });

// XMTP hook
const {
Expand Down Expand Up @@ -265,23 +186,6 @@
},
];

// Command suggestions logic
const getCommandSuggestions = (query: string): CommandSuggestion[] => {
if (!query.startsWith("/")) return [];

const commandQuery = query.slice(1).toLowerCase();
return commands.filter(cmd =>
cmd.name.toLowerCase().includes(commandQuery) ||
cmd.description.toLowerCase().includes(commandQuery)
).slice(0, 6).map(cmd => ({
id: cmd.id,
name: cmd.name,
description: cmd.description,
shortcut: cmd.shortcut,
}));
};

const suggestions = getCommandSuggestions(inputValue);

// Keyboard navigation
useKeyboard({
Expand Down Expand Up @@ -309,11 +213,6 @@
toggleCommandPalette();
return;
}
if (showSuggestions) {
setShowSuggestions(false);
setSelectedSuggestionIndex(0);
return;
}
if (isInputActive) {
setIsInputActive(false);
setInputValue("");
Expand Down Expand Up @@ -363,7 +262,7 @@
return;
}

if (cmd.startsWith("chat ")) {
if (cmd.startsWith("c ")) {
const parts = cmd.split(" ");
const index = parseInt(parts[1]) - 1;
if (
Expand Down Expand Up @@ -417,7 +316,7 @@
}
}

setErrorWithTimeout("Unknown command. Try /back, /list, /chat <n>, /new <address>, /refresh, or /exit");
setErrorWithTimeout("Unknown command. Try /b, /c &lt;n&gt;, /new &lt;address&gt;, /refresh, or /exit");
return;
}

Expand Down Expand Up @@ -451,8 +350,8 @@
</Box>
{agent && (
<Box flexDirection="column" marginLeft={2}>
<Text dimColor>✓ Agent initialized</Text>
<Text dimColor>
<Text color={DIM_GREY}>✓ Agent initialized</Text>
<Text color={DIM_GREY}>
Address: {address.slice(0, 10)}...{address.slice(-8)}
</Text>
</Box>
Expand Down Expand Up @@ -481,10 +380,6 @@
commands={commands}
onCommandExecute={(cmd) => cmd.action()}
onCommandPaletteClose={() => toggleCommandPalette()}
suggestions={suggestions}
selectedSuggestionIndex={selectedSuggestionIndex}
showSuggestions={showSuggestions}
onSuggestionSelect={handleSuggestionSelect}
/>
);
};
Expand Down
8 changes: 4 additions & 4 deletions src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const ChatView: React.FC<ChatViewProps> = ({
if (!conversation) {
// Show conversation selector instead of empty state
return (
<Box flexDirection="column" minHeight={height}>
<Box flexDirection="column" height={height} minHeight={height}>
<ConversationSelector
conversations={allConversations}
selectedIndex={selectedConversationIndex}
Expand All @@ -58,17 +58,17 @@ export const ChatView: React.FC<ChatViewProps> = ({
}

return (
<Box flexDirection="column" minHeight={height}>
<Box flexDirection="column" height={height} minHeight={height}>
{/* Chat header */}
<Box borderColor="gray" paddingX={0} marginBottom={1}>
<Box borderColor="gray" paddingX={0} marginBottom={1} flexShrink={0}>
<Text bold color={RED}>
{conversation.type === "group" ? "👥 GROUP: " : "💬 DM: "}
{conversation.name}
</Text>
</Box>

{/* Messages */}
<Box flexDirection="column" flexGrow={1}>
<Box flexDirection="column" flexGrow={1} minHeight={0}>
{visibleMessages.length === 0 ? (
<Text dimColor>No messages yet...</Text>
) : (
Expand Down
27 changes: 14 additions & 13 deletions src/components/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React, { useState, useEffect } from "react";
import { Box, Text, useInput } from "ink";
import TextInput from "ink-text-input";

const RED = "#fc4c34";
const DIM_GREY = "#666666";
const LIGHT_GREY = "#888888";

export interface Command {
id: string;
Expand Down Expand Up @@ -79,21 +80,21 @@ export const CommandPalette: React.FC<CommandPaletteProps> = ({
<Box
flexDirection="column"
borderStyle="double"
borderColor={RED}
borderColor={LIGHT_GREY}
paddingX={1}
paddingY={1}
>
{/* Header */}
<Box marginBottom={1}>
<Text bold color={RED}>
<Text bold color={LIGHT_GREY}>
Command Palette
</Text>
<Text dimColor> (Press Esc to close)</Text>
<Text color={DIM_GREY}> (Press Esc to close)</Text>
</Box>

{/* Search input */}
<Box marginBottom={1} borderStyle="single" borderColor="gray" paddingX={1}>
<Text color={RED}>❯ </Text>
<Box marginBottom={1} borderStyle="single" borderColor={DIM_GREY} paddingX={1}>
<Text color={LIGHT_GREY}>❯ </Text>
<TextInput
value={query}
onChange={setQuery}
Expand All @@ -106,21 +107,21 @@ export const CommandPalette: React.FC<CommandPaletteProps> = ({
{/* Command list */}
<Box flexDirection="column" minHeight={5}>
{filteredCommands.length === 0 ? (
<Text dimColor>No commands found</Text>
<Text color={DIM_GREY}>No commands found</Text>
) : (
filteredCommands.slice(0, 10).map((cmd, index) => {
const isSelected = index === selectedIndex;
return (
<Box key={cmd.id}>
<Text color={isSelected ? RED : undefined}>
<Text color={isSelected ? LIGHT_GREY : undefined}>
{isSelected ? "▶ " : " "}
</Text>
<Text bold={isSelected} color={isSelected ? RED : undefined}>
<Text bold={isSelected} color={isSelected ? LIGHT_GREY : undefined}>
{cmd.name}
</Text>
<Text dimColor> - {cmd.description}</Text>
<Text color={DIM_GREY}> - {cmd.description}</Text>
{cmd.shortcut && (
<Text color="gray"> ({cmd.shortcut})</Text>
<Text color={DIM_GREY}> ({cmd.shortcut})</Text>
)}
</Box>
);
Expand All @@ -129,8 +130,8 @@ export const CommandPalette: React.FC<CommandPaletteProps> = ({
</Box>

{/* Footer */}
<Box marginTop={1} borderStyle="single" borderColor="gray" paddingX={1}>
<Text dimColor>↑↓: Navigate • Enter: Execute • Esc: Close</Text>
<Box marginTop={1} borderStyle="single" borderColor={DIM_GREY} paddingX={1}>
<Text color={DIM_GREY}>↑↓: Navigate • Enter: Execute • Esc: Close</Text>
</Box>
</Box>
);
Expand Down
71 changes: 0 additions & 71 deletions src/components/CommandSuggestions.tsx

This file was deleted.

Loading
Loading