Skip to content

Commit 548cce3

Browse files
0xrinegadeclaude
andcommitted
feat(tui): Add AI Chat interface as default tab and Meshtastic BBS integration
## AI Chat Interface (Tenere-inspired) **Primary Feature: Chat Tab (Tab 0)** - New default view when launching research dashboard - Full conversation history with user/assistant message styling - Vim-inspired input system (i to activate, Enter to send, Esc to cancel) - Smart scrolling with j/k navigation and auto-scroll to new messages - Visual status indicators (⏳ Sending, ✓ Delivered, ⋯ Streaming, ✗ Error) - Welcome message with example blockchain investigation queries **Data Structures:** - `ChatMessage` struct with role, content, timestamp, and MessageStatus - `MessageStatus` enum for state management - Thread-safe `Arc<Mutex<Vec<ChatMessage>>>` for message storage **UI Components:** - `render_chat()` - Main chat layout with header, messages, input, and status bar - `render_chat_messages()` - Scrollable message display with proper styling - `render_chat_input()` - Input box with active/inactive states and cursor **Keybindings:** - `0` - Switch to Chat tab (new) - `i` - Activate chat input mode - `Enter` - Send message (when in input mode) - `Esc` - Cancel input - `j/k` - Scroll chat history (when not typing) - `Backspace` - Delete characters **Tab Navigation Updates:** - Chat is Tab 0 (default), Dashboard is Tab 1, Graph is Tab 2, Logs is Tab 3, Search is Tab 4, BBS is Tab 5 - Updated `next_tab()` and `previous_tab()` to include Chat in cycle - Updated header tab indicators with Chat tab icon - Updated help documentation with new tab numbers and Chat keybindings ## Meshtastic BBS Integration (Tab 5) **New BBS Tab for Agent-Human Communication:** - Meshtastic-based bulletin board system for off-grid communication - `BBSTuiState` for managing BBS UI state - Integration with existing BBS infrastructure (boards, posts, moderators) **New Files:** - `src/clparse/bbs.rs` - BBS command-line parsing - `src/commands/bbs_handler.rs` - BBS command handling - `src/utils/bbs/db/moderators.rs` - Moderator database operations - `src/utils/bbs/meshtastic.rs` - Meshtastic protocol integration **Modified Files:** - `src/utils/tui/app.rs` - Main TUI updates for both Chat and BBS - `src/utils/bbs/*` - BBS module enhancements - `src/clparse.rs` - Command parsing for BBS - `src/commands/mod.rs` - BBS command routing - `src/main.rs` - BBS initialization - `crates/ovsm/src/compiler/ir.rs` - Compiler improvements **Architecture:** - Modular BBS system with separate database, models, schema, and TUI widgets - Ready for research agent integration via `send_chat_message()` method - Clean separation between Chat (AI research) and BBS (human messaging) **Build Status:** ✅ Compiled successfully with no errors or warnings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent c851c25 commit 548cce3

File tree

16 files changed

+2214
-26
lines changed

16 files changed

+2214
-26
lines changed

crates/ovsm/src/compiler/ir.rs

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,12 @@ impl IrGenerator {
184184
// Entry point
185185
self.emit(IrInstruction::Label("entry".to_string()));
186186

187+
eprintln!("🔍 IR DEBUG: Generating IR for {} statements", program.statements.len());
188+
187189
// Generate IR for each statement, tracking last result
188190
let mut _last_result: Option<IrReg> = None;
189-
for typed_stmt in &program.statements {
191+
for (i, typed_stmt) in program.statements.iter().enumerate() {
192+
eprintln!(" Statement {}: {:?}", i, typed_stmt.statement);
190193
_last_result = self.generate_statement(&typed_stmt.statement)?;
191194
}
192195

@@ -562,6 +565,111 @@ impl IrGenerator {
562565
return Ok(Some(dst));
563566
}
564567

568+
// Handle (log :message msg :value val) - keyword-arg logging with sol_log_ syscall
569+
if name == "log" {
570+
eprintln!("🔍 IR DEBUG: log handler called with {} args", args.len());
571+
for (i, arg) in args.iter().enumerate() {
572+
eprintln!(" arg[{}]: name={:?}, value type={:?}", i, arg.name, arg.value);
573+
}
574+
// Parse keyword arguments
575+
let mut message_expr: Option<&Expression> = None;
576+
let mut value_expr: Option<&Expression> = None;
577+
578+
for arg in args {
579+
if let Some(ref kw) = arg.name {
580+
match kw.as_str() {
581+
"message" => message_expr = Some(&arg.value),
582+
"value" => value_expr = Some(&arg.value),
583+
_ => {} // Ignore unknown keywords
584+
}
585+
}
586+
}
587+
588+
// Build the log message
589+
let mut log_parts = Vec::new();
590+
591+
// Add message part if present
592+
if let Some(msg_expr) = message_expr {
593+
match msg_expr {
594+
Expression::StringLiteral(s) => {
595+
log_parts.push(s.clone());
596+
}
597+
_ => {
598+
// For non-literals, evaluate and try to convert
599+
// For now, we'll just skip non-string literals
600+
// TODO: Add runtime string formatting
601+
return Err(Error::runtime(
602+
"log :message must be a string literal for compilation"
603+
));
604+
}
605+
}
606+
}
607+
608+
// Add value part if present
609+
if let Some(val_expr) = value_expr {
610+
match val_expr {
611+
Expression::IntLiteral(n) => {
612+
log_parts.push(n.to_string());
613+
}
614+
Expression::FloatLiteral(f) => {
615+
log_parts.push(f.to_string());
616+
}
617+
Expression::BoolLiteral(b) => {
618+
log_parts.push(b.to_string());
619+
}
620+
Expression::StringLiteral(s) => {
621+
log_parts.push(s.clone());
622+
}
623+
_ => {
624+
// For dynamic values, use sol_log_64_ syscall instead
625+
// Evaluate the value expression
626+
let val_reg = self.generate_expr(val_expr)?
627+
.ok_or_else(|| Error::runtime("log value has no result"))?;
628+
629+
// If we have a message, log it first with sol_log_
630+
if !log_parts.is_empty() {
631+
let msg = log_parts.join(" ");
632+
let idx = self.strings.len();
633+
self.strings.push(msg.clone());
634+
let msg_reg = self.alloc_reg();
635+
self.emit(IrInstruction::ConstString(msg_reg, idx));
636+
self.emit(IrInstruction::Log(msg_reg, msg.len()));
637+
}
638+
639+
// Then log the dynamic value with sol_log_64_
640+
let dst = self.alloc_reg();
641+
self.emit(IrInstruction::Syscall(
642+
Some(dst),
643+
"sol_log_64_".to_string(),
644+
vec![val_reg],
645+
));
646+
return Ok(Some(dst));
647+
}
648+
}
649+
}
650+
651+
// If we have any log parts, emit a single Log instruction
652+
if !log_parts.is_empty() {
653+
let full_message = log_parts.join(" ");
654+
let idx = self.strings.len();
655+
self.strings.push(full_message.clone());
656+
657+
let msg_reg = self.alloc_reg();
658+
self.emit(IrInstruction::ConstString(msg_reg, idx));
659+
self.emit(IrInstruction::Log(msg_reg, full_message.len()));
660+
661+
// Return success register
662+
let dst = self.alloc_reg();
663+
self.emit(IrInstruction::ConstI64(dst, 0));
664+
return Ok(Some(dst));
665+
} else {
666+
// No arguments - just return success
667+
let dst = self.alloc_reg();
668+
self.emit(IrInstruction::ConstI64(dst, 0));
669+
return Ok(Some(dst));
670+
}
671+
}
672+
565673
// Handle (do expr1 expr2 ... exprN) - sequence of expressions, return last
566674
if name == "do" {
567675
let mut last_reg = None;

src/clparse.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use {
77
mod agent;
88
mod audit;
99
mod balance;
10+
mod bbs;
1011
mod chat;
1112
mod database;
1213
mod deploy;
@@ -263,6 +264,7 @@ Issues & feedback: https://github.com/opensvm/osvm-cli/issues",
263264
)
264265
// Core commands - using modular builders
265266
.subcommand(balance::build_balance_command())
267+
.subcommand(bbs::build_bbs_command())
266268
.subcommand(rpc::build_rpc_command())
267269
.subcommand(examples::build_examples_command())
268270
.subcommand(chat::build_chat_command())

0 commit comments

Comments
 (0)