blax
Version:
Blax - HMS-Powered Multi-Agent Platform with Government Agency Analysis, Deep Research, and Enterprise-Ready Deployment. No local LLM keys required.
313 lines • 9.1 kB
JavaScript
import React, { useState, useEffect, useCallback } from 'react';
import { render, Box, Text, useInput, useApp } from 'ink';
import TextInput from 'ink-text-input';
import { eventBus } from '../core/eventBus.js';
function App({ agentHub, hubAdapter }) {
const [messages, setMessages] = useState([
{
role: 'system',
content: '🦾 tlnt ready - Type your message below (F2: settings, F3: tasks, Ctrl+C: quit)',
timestamp: Date.now()
}
]);
const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [showSettings, setShowSettings] = useState(false);
const [showTasks, setShowTasks] = useState(false);
const [connectionStatus, setConnectionStatus] = useState('disconnected');
const { exit } = useApp();
// Handle keyboard shortcuts
useInput((input, key) => {
if (key.ctrl && input === 'c') {
exit();
}
else if (key.f2) {
setShowSettings(!showSettings);
}
else if (key.f3) {
setShowTasks(!showTasks);
}
});
// Monitor hub connection status
useEffect(() => {
const updateStatus = () => {
setConnectionStatus(hubAdapter.isConnected() ? 'connected' : 'disconnected');
};
hubAdapter.on('connected', updateStatus);
hubAdapter.on('disconnected', updateStatus);
updateStatus();
return () => {
hubAdapter.off('connected', updateStatus);
hubAdapter.off('disconnected', updateStatus);
};
}, [hubAdapter]);
// Listen to hub events
useEffect(() => {
const subscription = eventBus.subscribeToAgentEvents().subscribe(event => {
setMessages(prev => [...prev, {
role: 'system',
content: `[${event.type}] ${JSON.stringify(event.data)}`,
timestamp: event.timestamp
}]);
});
return () => subscription.unsubscribe();
}, []);
const handleSubmit = useCallback(async () => {
if (!input.trim() || isLoading)
return;
const userMessage = {
role: 'user',
content: input.trim(),
timestamp: Date.now()
};
setMessages(prev => [...prev, userMessage]);
setInput('');
setIsLoading(true);
try {
const result = await agentHub.execute('chat', {
sessionId: `tui-${Date.now()}`,
userId: 'tui-user',
workspacePath: process.cwd(),
environment: 'development',
capabilities: ['chat'],
metadata: {}
}, { prompt: input.trim() });
const assistantMessage = {
role: 'assistant',
content: result.success ? String(result.data) : `Error: ${result.error?.message}`,
timestamp: Date.now()
};
setMessages(prev => [...prev, assistantMessage]);
}
catch (error) {
const errorMessage = {
role: 'system',
content: `Error: ${error instanceof Error ? error.message : String(error)}`,
timestamp: Date.now()
};
setMessages(prev => [...prev, errorMessage]);
}
finally {
setIsLoading(false);
}
}, [input, isLoading, agentHub]);
if (showSettings) {
return onBack;
{
() => setShowSettings(false);
}
hubAdapter = { hubAdapter } / > ;
}
if (showTasks) {
return onBack;
{
() => setShowTasks(false);
}
hubAdapter = { hubAdapter } / > ;
}
return flexDirection = "column";
height = "100%" >
{ /* Header */}
< Box;
borderStyle = "single";
borderColor = "gray";
paddingX = { 1: } >
tlnt - Terminal;
Agent |
Status;
color;
{
connectionStatus === 'connected' ? 'green' : 'red';
}
> { connectionStatus } < /Text> |;
F2: Settings | F3;
Tasks | Ctrl + C;
Quit
< /Text>
< /Box>;
{ /* Chat Messages */ }
flexDirection;
"column";
flexGrow = { 1: };
paddingX = { 1: };
paddingY = { 1: } >
{ messages, : .map((message, index) => key = { index }, marginBottom = { 1: } >
color, {
message, : .role === 'user' ? 'cyan' :
message.role === 'assistant' ? 'green' :
'gray'
} >
[{ message, : .role }], { message, : .content }
< /Text>
< /Box>) };
{
isLoading && color;
"yellow" > ;
Thinking;
/Text>
< /Box>;
}
/Box>;
{ /* Input Area */ }
borderStyle;
"single";
borderColor = "gray";
paddingX = { 1: } >
color;
"cyan" > & gt;
/Text>
< TextInput;
value = { input };
onChange = { setInput };
onSubmit = { handleSubmit };
placeholder = "Type your message here..."
/ >
/Box>
< /Box>;
;
}
function SettingsView({ onBack, hubAdapter }) {
useInput((input, key) => {
if (key.escape || key.f2) {
onBack();
}
});
const status = hubAdapter.getConnectionStatus();
return flexDirection = "column";
padding = { 2: } >
marginBottom;
{
2;
}
>
bold;
color = "cyan" > Settings(Press, ESC, or, F2, to, go, back) < /Text>
< /Box>
< Box;
flexDirection = "column";
gap = { 1: } >
Hub;
URL: {
status.url;
}
/Text>
< Text > Connected;
{
status.connected ? 'Yes' : 'No';
}
/Text>
< Text > Reconnect;
Attempts: {
status.reconnectAttempts;
}
/Text>
< Text > Environment;
{
process.env.NODE_ENV || 'development';
}
/Text>
< Text > Working;
Directory: {
process.cwd();
}
/Text>
< /Box>
< /Box>;
;
}
function TasksView({ onBack, hubAdapter }) {
const [agents, setAgents] = useState([]);
const [deals, setDeals] = useState([]);
const [loading, setLoading] = useState(true);
useInput((input, key) => {
if (key.escape || key.f3) {
onBack();
}
});
useEffect(() => {
async function loadData() {
try {
if (hubAdapter.isConnected()) {
const [agentsData, dealsData] = await Promise.all([
hubAdapter.listAgents().catch(() => []),
hubAdapter.listDeals().catch(() => [])
]);
setAgents(agentsData);
setDeals(dealsData);
}
}
finally {
setLoading(false);
}
}
loadData();
}, [hubAdapter]);
return flexDirection = "column";
padding = { 2: } >
marginBottom;
{
2;
}
>
bold;
color = "cyan" > Tasks & Agents(Press, ESC, or, F3, to, go, back) < /Text>
< /Box>;
{
loading ? Loading : ;
/Text>;
flexDirection = "column";
gap = { 1: } >
bold > Active;
Agents({ agents, : .length }) < /Text>;
{
agents.length === 0 ? color = "gray" > No : ;
agents;
available < /Text>;
(agents.map((agent, index) => key = { index } >
, { agent, : .name }({ agent, : .status })
< /Text>));
}
bold;
marginTop = { 1: } > Active;
Deals({ deals, : .length }) < /Text>;
{
deals.length === 0 ? color = "gray" > No : ;
deals;
available < /Text>;
(deals.map((deal, index) => key = { index } >
, { deal, : .name }({ deal, : .status }) - { deal, : .participants.length }, participants
< /Text>));
}
/Box>;
}
/Box>;
;
}
export class TUI {
agentHub;
hubAdapter;
constructor(agentHub, hubAdapter) {
this.agentHub = agentHub;
this.hubAdapter = hubAdapter;
}
async start() {
// Clear screen and set up terminal
process.stdout.write('\x1Bc'); // Clear screen
process.stdout.write('\x1b[?1049h'); // Use alternate screen buffer
// Handle cleanup on exit
process.on('SIGINT', this.cleanup);
process.on('SIGTERM', this.cleanup);
process.on('exit', this.cleanup);
// Render the React app
render(React.createElement(App, {
agentHub: this.agentHub,
hubAdapter: this.hubAdapter
}));
}
cleanup = () => {
// Restore terminal
process.stdout.write('\x1b[?1049l'); // Exit alternate screen buffer
this.hubAdapter.disconnect();
};
}
//# sourceMappingURL=tui.js.map