chore: standardize string quotes and fix import ordering across multiple modules

This commit is contained in:
2025-11-04 07:09:12 +00:00
parent ea29bdc403
commit e9ced4a493
82 changed files with 4963 additions and 3094 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
from pr.commands.handlers import handle_command
__all__ = ['handle_command']
__all__ = ["handle_command"]
+162 -98
View File
@@ -1,30 +1,35 @@
import json
import time
from pr.ui import Colors
from pr.autonomous import run_autonomous_mode
from pr.core.api import list_models
from pr.tools import read_file
from pr.tools.base import get_tools_definition
from pr.core.api import list_models
from pr.autonomous import run_autonomous_mode
from pr.ui import Colors
def handle_command(assistant, command):
command_parts = command.strip().split(maxsplit=1)
cmd = command_parts[0].lower()
if cmd == '/auto':
if cmd == "/auto":
if len(command_parts) < 2:
print(f"{Colors.RED}Usage: /auto [task description]{Colors.RESET}")
print(f"{Colors.GRAY}Example: /auto Create a Python web scraper for news sites{Colors.RESET}")
print(
f"{Colors.GRAY}Example: /auto Create a Python web scraper for news sites{Colors.RESET}"
)
return True
task = command_parts[1]
run_autonomous_mode(assistant, task)
return True
if cmd in ['exit', 'quit', 'q']:
if cmd in ["exit", "quit", "q"]:
return False
elif cmd == 'help':
print(f"""
elif cmd == "help":
print(
f"""
{Colors.BOLD}Available Commands:{Colors.RESET}
{Colors.BOLD}Basic:{Colors.RESET}
@@ -54,18 +59,21 @@ def handle_command(assistant, command):
{Colors.CYAN}/cache{Colors.RESET} - Show cache statistics
{Colors.CYAN}/cache clear{Colors.RESET} - Clear all caches
{Colors.CYAN}/stats{Colors.RESET} - Show system statistics
""")
"""
)
elif cmd == '/reset':
elif cmd == "/reset":
assistant.messages = assistant.messages[:1]
print(f"{Colors.GREEN}Message history cleared{Colors.RESET}")
elif cmd == '/dump':
elif cmd == "/dump":
print(json.dumps(assistant.messages, indent=2))
elif cmd == '/verbose':
elif cmd == "/verbose":
assistant.verbose = not assistant.verbose
print(f"Verbose mode: {Colors.GREEN if assistant.verbose else Colors.RED}{'ON' if assistant.verbose else 'OFF'}{Colors.RESET}")
print(
f"Verbose mode: {Colors.GREEN if assistant.verbose else Colors.RED}{'ON' if assistant.verbose else 'OFF'}{Colors.RESET}"
)
elif cmd.startswith("/model"):
if len(command_parts) < 2:
@@ -74,77 +82,81 @@ def handle_command(assistant, command):
assistant.model = command_parts[1]
print(f"Model set to: {Colors.GREEN}{assistant.model}{Colors.RESET}")
elif cmd == '/models':
elif cmd == "/models":
models = list_models(assistant.model_list_url, assistant.api_key)
if isinstance(models, dict) and 'error' in models:
if isinstance(models, dict) and "error" in models:
print(f"{Colors.RED}Error fetching models: {models['error']}{Colors.RESET}")
else:
print(f"{Colors.BOLD}Available Models:{Colors.RESET}")
for model in models:
print(f"{Colors.CYAN}{model['id']}{Colors.RESET}")
elif cmd == '/tools':
elif cmd == "/tools":
print(f"{Colors.BOLD}Available Tools:{Colors.RESET}")
for tool in get_tools_definition():
func = tool['function']
print(f"{Colors.CYAN}{func['name']}{Colors.RESET}: {func['description']}")
func = tool["function"]
print(
f"{Colors.CYAN}{func['name']}{Colors.RESET}: {func['description']}"
)
elif cmd == '/review' and len(command_parts) > 1:
elif cmd == "/review" and len(command_parts) > 1:
filename = command_parts[1]
review_file(assistant, filename)
elif cmd == '/refactor' and len(command_parts) > 1:
elif cmd == "/refactor" and len(command_parts) > 1:
filename = command_parts[1]
refactor_file(assistant, filename)
elif cmd == '/obfuscate' and len(command_parts) > 1:
elif cmd == "/obfuscate" and len(command_parts) > 1:
filename = command_parts[1]
obfuscate_file(assistant, filename)
elif cmd == '/workflows':
elif cmd == "/workflows":
show_workflows(assistant)
elif cmd == '/workflow' and len(command_parts) > 1:
elif cmd == "/workflow" and len(command_parts) > 1:
workflow_name = command_parts[1]
execute_workflow_command(assistant, workflow_name)
elif cmd == '/agent' and len(command_parts) > 1:
elif cmd == "/agent" and len(command_parts) > 1:
args = command_parts[1].split(maxsplit=1)
if len(args) < 2:
print(f"{Colors.RED}Usage: /agent <role> <task>{Colors.RESET}")
print(f"{Colors.GRAY}Available roles: coding, research, data_analysis, planning, testing, documentation{Colors.RESET}")
print(
f"{Colors.GRAY}Available roles: coding, research, data_analysis, planning, testing, documentation{Colors.RESET}"
)
else:
role, task = args[0], args[1]
execute_agent_task(assistant, role, task)
elif cmd == '/agents':
elif cmd == "/agents":
show_agents(assistant)
elif cmd == '/collaborate' and len(command_parts) > 1:
elif cmd == "/collaborate" and len(command_parts) > 1:
task = command_parts[1]
collaborate_agents_command(assistant, task)
elif cmd == '/knowledge' and len(command_parts) > 1:
elif cmd == "/knowledge" and len(command_parts) > 1:
query = command_parts[1]
search_knowledge(assistant, query)
elif cmd == '/remember' and len(command_parts) > 1:
elif cmd == "/remember" and len(command_parts) > 1:
content = command_parts[1]
store_knowledge(assistant, content)
elif cmd == '/history':
elif cmd == "/history":
show_conversation_history(assistant)
elif cmd == '/cache':
if len(command_parts) > 1 and command_parts[1].lower() == 'clear':
elif cmd == "/cache":
if len(command_parts) > 1 and command_parts[1].lower() == "clear":
clear_caches(assistant)
else:
show_cache_stats(assistant)
elif cmd == '/stats':
elif cmd == "/stats":
show_system_stats(assistant)
elif cmd.startswith('/bg'):
elif cmd.startswith("/bg"):
handle_background_command(assistant, command)
else:
@@ -152,35 +164,46 @@ def handle_command(assistant, command):
return True
def review_file(assistant, filename):
result = read_file(filename)
if result['status'] == 'success':
message = f"Please review this file and provide feedback:\n\n{result['content']}"
if result["status"] == "success":
message = (
f"Please review this file and provide feedback:\n\n{result['content']}"
)
from pr.core.assistant import process_message
process_message(assistant, message)
else:
print(f"{Colors.RED}Error reading file: {result['error']}{Colors.RESET}")
def refactor_file(assistant, filename):
result = read_file(filename)
if result['status'] == 'success':
message = f"Please refactor this code to improve its quality:\n\n{result['content']}"
if result["status"] == "success":
message = (
f"Please refactor this code to improve its quality:\n\n{result['content']}"
)
from pr.core.assistant import process_message
process_message(assistant, message)
else:
print(f"{Colors.RED}Error reading file: {result['error']}{Colors.RESET}")
def obfuscate_file(assistant, filename):
result = read_file(filename)
if result['status'] == 'success':
if result["status"] == "success":
message = f"Please obfuscate this code:\n\n{result['content']}"
from pr.core.assistant import process_message
process_message(assistant, message)
else:
print(f"{Colors.RED}Error reading file: {result['error']}{Colors.RESET}")
def show_workflows(assistant):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
@@ -194,23 +217,25 @@ def show_workflows(assistant):
print(f"{Colors.CYAN}{wf['name']}{Colors.RESET}: {wf['description']}")
print(f" Executions: {wf['execution_count']}")
def execute_workflow_command(assistant, workflow_name):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
print(f"{Colors.YELLOW}Executing workflow: {workflow_name}...{Colors.RESET}")
result = assistant.enhanced.execute_workflow(workflow_name)
if 'error' in result:
if "error" in result:
print(f"{Colors.RED}Error: {result['error']}{Colors.RESET}")
else:
print(f"{Colors.GREEN}Workflow completed successfully{Colors.RESET}")
print(f"Execution ID: {result['execution_id']}")
print(f"Results: {json.dumps(result['results'], indent=2)}")
def execute_agent_task(assistant, role, task):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
@@ -221,14 +246,15 @@ def execute_agent_task(assistant, role, task):
print(f"{Colors.YELLOW}Executing task...{Colors.RESET}")
result = assistant.enhanced.agent_task(agent_id, task)
if 'error' in result:
if "error" in result:
print(f"{Colors.RED}Error: {result['error']}{Colors.RESET}")
else:
print(f"\n{Colors.GREEN}{role.capitalize()} Agent Response:{Colors.RESET}")
print(result['response'])
print(result["response"])
def show_agents(assistant):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
@@ -236,37 +262,39 @@ def show_agents(assistant):
print(f"\n{Colors.BOLD}Agent Session Summary:{Colors.RESET}")
print(f"Active agents: {summary['active_agents']}")
if summary['agents']:
for agent in summary['agents']:
if summary["agents"]:
for agent in summary["agents"]:
print(f"\n{Colors.CYAN}{agent['agent_id']}{Colors.RESET}")
print(f" Role: {agent['role']}")
print(f" Tasks completed: {agent['task_count']}")
print(f" Messages: {agent['message_count']}")
def collaborate_agents_command(assistant, task):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
print(f"{Colors.YELLOW}Initiating agent collaboration...{Colors.RESET}")
roles = ['coding', 'research', 'planning']
roles = ["coding", "research", "planning"]
result = assistant.enhanced.collaborate_agents(task, roles)
print(f"\n{Colors.GREEN}Collaboration completed{Colors.RESET}")
print(f"\nOrchestrator response:")
if 'orchestrator' in result and 'response' in result['orchestrator']:
print(result['orchestrator']['response'])
if "orchestrator" in result and "response" in result["orchestrator"]:
print(result["orchestrator"]["response"])
if result.get('agents'):
if result.get("agents"):
print(f"\n{Colors.BOLD}Agent Results:{Colors.RESET}")
for agent_result in result['agents']:
if 'role' in agent_result:
for agent_result in result["agents"]:
if "role" in agent_result:
print(f"\n{Colors.CYAN}{agent_result['role']}:{Colors.RESET}")
print(agent_result.get('response', 'No response'))
print(agent_result.get("response", "No response"))
def search_knowledge(assistant, query):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
@@ -282,13 +310,15 @@ def search_knowledge(assistant, query):
print(f" {entry.content[:200]}...")
print(f" Accessed: {entry.access_count} times")
def store_knowledge(assistant, content):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
import uuid
import time
import uuid
from pr.memory import KnowledgeEntry
categories = assistant.enhanced.fact_extractor.categorize_content(content)
@@ -296,11 +326,11 @@ def store_knowledge(assistant, content):
entry = KnowledgeEntry(
entry_id=entry_id,
category=categories[0] if categories else 'general',
category=categories[0] if categories else "general",
content=content,
metadata={'manual_entry': True},
metadata={"manual_entry": True},
created_at=time.time(),
updated_at=time.time()
updated_at=time.time(),
)
assistant.enhanced.knowledge_store.add_entry(entry)
@@ -308,8 +338,9 @@ def store_knowledge(assistant, content):
print(f"Entry ID: {entry_id}")
print(f"Category: {entry.category}")
def show_conversation_history(assistant):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
@@ -322,17 +353,21 @@ def show_conversation_history(assistant):
print(f"\n{Colors.BOLD}Recent Conversations:{Colors.RESET}")
for conv in history:
import datetime
started = datetime.datetime.fromtimestamp(conv['started_at']).strftime('%Y-%m-%d %H:%M')
started = datetime.datetime.fromtimestamp(conv["started_at"]).strftime(
"%Y-%m-%d %H:%M"
)
print(f"\n{Colors.CYAN}{conv['conversation_id']}{Colors.RESET}")
print(f" Started: {started}")
print(f" Messages: {conv['message_count']}")
if conv.get('summary'):
if conv.get("summary"):
print(f" Summary: {conv['summary'][:100]}...")
if conv.get('topics'):
if conv.get("topics"):
print(f" Topics: {', '.join(conv['topics'])}")
def show_cache_stats(assistant):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
@@ -340,36 +375,40 @@ def show_cache_stats(assistant):
print(f"\n{Colors.BOLD}Cache Statistics:{Colors.RESET}")
if 'api_cache' in stats:
api_stats = stats['api_cache']
if "api_cache" in stats:
api_stats = stats["api_cache"]
print(f"\n{Colors.CYAN}API Cache:{Colors.RESET}")
print(f" Total entries: {api_stats['total_entries']}")
print(f" Valid entries: {api_stats['valid_entries']}")
print(f" Expired entries: {api_stats['expired_entries']}")
print(f" Cached tokens: {api_stats['total_cached_tokens']}")
if 'tool_cache' in stats:
tool_stats = stats['tool_cache']
if "tool_cache" in stats:
tool_stats = stats["tool_cache"]
print(f"\n{Colors.CYAN}Tool Cache:{Colors.RESET}")
print(f" Total entries: {tool_stats['total_entries']}")
print(f" Valid entries: {tool_stats['valid_entries']}")
print(f" Total cache hits: {tool_stats['total_cache_hits']}")
if tool_stats.get('by_tool'):
if tool_stats.get("by_tool"):
print(f"\n Per-tool statistics:")
for tool_name, tool_stat in tool_stats['by_tool'].items():
print(f" {tool_name}: {tool_stat['cached_entries']} entries, {tool_stat['total_hits']} hits")
for tool_name, tool_stat in tool_stats["by_tool"].items():
print(
f" {tool_name}: {tool_stat['cached_entries']} entries, {tool_stat['total_hits']} hits"
)
def clear_caches(assistant):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
assistant.enhanced.clear_caches()
print(f"{Colors.GREEN}All caches cleared successfully{Colors.RESET}")
def show_system_stats(assistant):
if not hasattr(assistant, 'enhanced'):
if not hasattr(assistant, "enhanced"):
print(f"{Colors.YELLOW}Enhanced features not initialized{Colors.RESET}")
return
@@ -388,68 +427,81 @@ def show_system_stats(assistant):
print(f"\n{Colors.CYAN}Active Agents:{Colors.RESET}")
print(f" Count: {agent_summary['active_agents']}")
if 'api_cache' in cache_stats:
if "api_cache" in cache_stats:
print(f"\n{Colors.CYAN}Caching:{Colors.RESET}")
print(f" API cache entries: {cache_stats['api_cache']['valid_entries']}")
if 'tool_cache' in cache_stats:
if "tool_cache" in cache_stats:
print(f" Tool cache entries: {cache_stats['tool_cache']['valid_entries']}")
def handle_background_command(assistant, command):
"""Handle background multiplexer commands."""
parts = command.strip().split(maxsplit=2)
if len(parts) < 2:
print(f"{Colors.RED}Usage: /bg <subcommand> [args]{Colors.RESET}")
print(f"{Colors.GRAY}Available subcommands: start, list, status, output, input, kill, events{Colors.RESET}")
print(
f"{Colors.GRAY}Available subcommands: start, list, status, output, input, kill, events{Colors.RESET}"
)
return
subcmd = parts[1].lower()
try:
if subcmd == 'start' and len(parts) >= 3:
if subcmd == "start" and len(parts) >= 3:
session_name = f"bg_{len(parts[2].split())}_{int(time.time())}"
start_background_session(assistant, session_name, parts[2])
elif subcmd == 'list':
elif subcmd == "list":
list_background_sessions(assistant)
elif subcmd == 'status' and len(parts) >= 3:
elif subcmd == "status" and len(parts) >= 3:
show_session_status(assistant, parts[2])
elif subcmd == 'output' and len(parts) >= 3:
elif subcmd == "output" and len(parts) >= 3:
show_session_output(assistant, parts[2])
elif subcmd == 'input' and len(parts) >= 4:
elif subcmd == "input" and len(parts) >= 4:
send_session_input(assistant, parts[2], parts[3])
elif subcmd == 'kill' and len(parts) >= 3:
elif subcmd == "kill" and len(parts) >= 3:
kill_background_session(assistant, parts[2])
elif subcmd == 'events':
elif subcmd == "events":
show_background_events(assistant)
else:
print(f"{Colors.RED}Unknown background command: {subcmd}{Colors.RESET}")
print(f"{Colors.GRAY}Available: start, list, status, output, input, kill, events{Colors.RESET}")
print(
f"{Colors.GRAY}Available: start, list, status, output, input, kill, events{Colors.RESET}"
)
except Exception as e:
print(f"{Colors.RED}Error executing background command: {e}{Colors.RESET}")
def start_background_session(assistant, session_name, command):
"""Start a command in background."""
try:
from pr.multiplexer import start_background_process
result = start_background_process(session_name, command)
if result['status'] == 'success':
print(f"{Colors.GREEN}Started background session '{session_name}' with PID {result['pid']}{Colors.RESET}")
if result["status"] == "success":
print(
f"{Colors.GREEN}Started background session '{session_name}' with PID {result['pid']}{Colors.RESET}"
)
else:
print(f"{Colors.RED}Failed to start background session: {result.get('error', 'Unknown error')}{Colors.RESET}")
print(
f"{Colors.RED}Failed to start background session: {result.get('error', 'Unknown error')}{Colors.RESET}"
)
except Exception as e:
print(f"{Colors.RED}Error starting background session: {e}{Colors.RESET}")
def list_background_sessions(assistant):
"""List all background sessions."""
try:
from pr.ui.display import display_multiplexer_status
from pr.multiplexer import get_all_sessions
from pr.ui.display import display_multiplexer_status
sessions = get_all_sessions()
display_multiplexer_status(sessions)
except Exception as e:
print(f"{Colors.RED}Error listing background sessions: {e}{Colors.RESET}")
def show_session_status(assistant, session_name):
"""Show status of a specific session."""
try:
@@ -461,15 +513,17 @@ def show_session_status(assistant, session_name):
print(f" Status: {info.get('status', 'unknown')}")
print(f" PID: {info.get('pid', 'N/A')}")
print(f" Command: {info.get('command', 'N/A')}")
if 'start_time' in info:
if "start_time" in info:
import time
elapsed = time.time() - info['start_time']
elapsed = time.time() - info["start_time"]
print(f" Running for: {elapsed:.1f}s")
else:
print(f"{Colors.YELLOW}Session '{session_name}' not found{Colors.RESET}")
except Exception as e:
print(f"{Colors.RED}Error getting session status: {e}{Colors.RESET}")
def show_session_output(assistant, session_name):
"""Show output of a specific session."""
try:
@@ -482,36 +536,45 @@ def show_session_output(assistant, session_name):
for line in output:
print(line)
else:
print(f"{Colors.YELLOW}No output available for session '{session_name}'{Colors.RESET}")
print(
f"{Colors.YELLOW}No output available for session '{session_name}'{Colors.RESET}"
)
except Exception as e:
print(f"{Colors.RED}Error getting session output: {e}{Colors.RESET}")
def send_session_input(assistant, session_name, input_text):
"""Send input to a background session."""
try:
from pr.multiplexer import send_input_to_session
result = send_input_to_session(session_name, input_text)
if result['status'] == 'success':
if result["status"] == "success":
print(f"{Colors.GREEN}Input sent to session '{session_name}'{Colors.RESET}")
else:
print(f"{Colors.RED}Failed to send input: {result.get('error', 'Unknown error')}{Colors.RESET}")
print(
f"{Colors.RED}Failed to send input: {result.get('error', 'Unknown error')}{Colors.RESET}"
)
except Exception as e:
print(f"{Colors.RED}Error sending input: {e}{Colors.RESET}")
def kill_background_session(assistant, session_name):
"""Kill a background session."""
try:
from pr.multiplexer import kill_session
result = kill_session(session_name)
if result['status'] == 'success':
if result["status"] == "success":
print(f"{Colors.GREEN}Session '{session_name}' terminated{Colors.RESET}")
else:
print(f"{Colors.RED}Failed to kill session: {result.get('error', 'Unknown error')}{Colors.RESET}")
print(
f"{Colors.RED}Failed to kill session: {result.get('error', 'Unknown error')}{Colors.RESET}"
)
except Exception as e:
print(f"{Colors.RED}Error killing session: {e}{Colors.RESET}")
def show_background_events(assistant):
"""Show recent background events."""
try:
@@ -526,6 +589,7 @@ def show_background_events(assistant):
for event in events[-10:]: # Show last 10 events
from pr.ui.display import display_background_event
display_background_event(event)
else:
print(f"{Colors.GRAY}No recent background events{Colors.RESET}")
+72 -40
View File
@@ -1,11 +1,15 @@
from pr.tools.interactive_control import (
list_active_sessions, get_session_status, read_session_output,
send_input_to_session, close_interactive_session
)
from pr.multiplexer import get_multiplexer
from pr.tools.interactive_control import (
close_interactive_session,
get_session_status,
list_active_sessions,
read_session_output,
send_input_to_session,
)
from pr.tools.prompt_detection import get_global_detector
from pr.ui import Colors
def show_sessions(args=None):
"""Show all active multiplexer sessions."""
sessions = list_active_sessions()
@@ -18,24 +22,29 @@ def show_sessions(args=None):
print("-" * 80)
for session_name, session_data in sessions.items():
metadata = session_data['metadata']
output_summary = session_data['output_summary']
metadata = session_data["metadata"]
output_summary = session_data["output_summary"]
status = get_session_status(session_name)
is_active = status.get('is_active', False) if status else False
is_active = status.get("is_active", False) if status else False
status_color = Colors.GREEN if is_active else Colors.RED
print(f"{Colors.CYAN}{session_name}{Colors.RESET}: {status_color}{metadata.get('process_type', 'unknown')}{Colors.RESET}")
print(
f"{Colors.CYAN}{session_name}{Colors.RESET}: {status_color}{metadata.get('process_type', 'unknown')}{Colors.RESET}"
)
if status and 'pid' in status:
if status and "pid" in status:
print(f" PID: {status['pid']}")
print(f" Age: {metadata.get('start_time', 0):.1f}s")
print(f" Output: {output_summary['stdout_lines']} stdout, {output_summary['stderr_lines']} stderr lines")
print(
f" Output: {output_summary['stdout_lines']} stdout, {output_summary['stderr_lines']} stderr lines"
)
print(f" Interactions: {metadata.get('interaction_count', 0)}")
print(f" State: {metadata.get('state', 'unknown')}")
print()
def attach_session(args):
"""Attach to a session (show its output and allow interaction)."""
if not args or len(args) < 1:
@@ -56,20 +65,23 @@ def attach_session(args):
# Show recent output
try:
output = read_session_output(session_name, lines=20)
if output['stdout']:
if output["stdout"]:
print(f"{Colors.GRAY}Recent stdout:{Colors.RESET}")
for line in output['stdout'].split('\n'):
for line in output["stdout"].split("\n"):
if line.strip():
print(f" {line}")
if output['stderr']:
if output["stderr"]:
print(f"{Colors.YELLOW}Recent stderr:{Colors.RESET}")
for line in output['stderr'].split('\n'):
for line in output["stderr"].split("\n"):
if line.strip():
print(f" {line}")
except Exception as e:
print(f"{Colors.RED}Error reading output: {e}{Colors.RESET}")
print(f"\n{Colors.CYAN}Session is {'active' if status.get('is_active') else 'inactive'}{Colors.RESET}")
print(
f"\n{Colors.CYAN}Session is {'active' if status.get('is_active') else 'inactive'}{Colors.RESET}"
)
def detach_session(args):
"""Detach from a session (stop showing its output but keep it running)."""
@@ -87,7 +99,10 @@ def detach_session(args):
# In this implementation, detaching just means we stop displaying output
# The session continues to run in the background
mux.show_output = False
print(f"{Colors.GREEN}Detached from session '{session_name}'. It continues running in background.{Colors.RESET}")
print(
f"{Colors.GREEN}Detached from session '{session_name}'. It continues running in background.{Colors.RESET}"
)
def kill_session(args):
"""Kill a session forcefully."""
@@ -101,7 +116,10 @@ def kill_session(args):
close_interactive_session(session_name)
print(f"{Colors.GREEN}Session '{session_name}' terminated.{Colors.RESET}")
except Exception as e:
print(f"{Colors.RED}Error terminating session '{session_name}': {e}{Colors.RESET}")
print(
f"{Colors.RED}Error terminating session '{session_name}': {e}{Colors.RESET}"
)
def send_command(args):
"""Send a command to a session."""
@@ -110,13 +128,18 @@ def send_command(args):
return
session_name = args[0]
command = ' '.join(args[1:])
command = " ".join(args[1:])
try:
send_input_to_session(session_name, command)
print(f"{Colors.GREEN}Sent command to '{session_name}': {command}{Colors.RESET}")
print(
f"{Colors.GREEN}Sent command to '{session_name}': {command}{Colors.RESET}"
)
except Exception as e:
print(f"{Colors.RED}Error sending command to '{session_name}': {e}{Colors.RESET}")
print(
f"{Colors.RED}Error sending command to '{session_name}': {e}{Colors.RESET}"
)
def show_session_log(args):
"""Show the full log/output of a session."""
@@ -131,19 +154,20 @@ def show_session_log(args):
print(f"{Colors.BOLD}Full log for session: {session_name}{Colors.RESET}")
print("=" * 80)
if output['stdout']:
if output["stdout"]:
print(f"{Colors.GRAY}STDOUT:{Colors.RESET}")
print(output['stdout'])
print(output["stdout"])
print()
if output['stderr']:
if output["stderr"]:
print(f"{Colors.YELLOW}STDERR:{Colors.RESET}")
print(output['stderr'])
print(output["stderr"])
print()
except Exception as e:
print(f"{Colors.RED}Error reading log for '{session_name}': {e}{Colors.RESET}")
def show_session_status(args):
"""Show detailed status of a session."""
if not args or len(args) < 1:
@@ -160,11 +184,11 @@ def show_session_status(args):
print(f"{Colors.BOLD}Status for session: {session_name}{Colors.RESET}")
print("-" * 50)
metadata = status.get('metadata', {})
metadata = status.get("metadata", {})
print(f"Process type: {metadata.get('process_type', 'unknown')}")
print(f"Active: {status.get('is_active', False)}")
if 'pid' in status:
if "pid" in status:
print(f"PID: {status['pid']}")
print(f"Start time: {metadata.get('start_time', 0):.1f}")
@@ -172,8 +196,10 @@ def show_session_status(args):
print(f"Interaction count: {metadata.get('interaction_count', 0)}")
print(f"State: {metadata.get('state', 'unknown')}")
output_summary = status.get('output_summary', {})
print(f"Output lines: {output_summary.get('stdout_lines', 0)} stdout, {output_summary.get('stderr_lines', 0)} stderr")
output_summary = status.get("output_summary", {})
print(
f"Output lines: {output_summary.get('stdout_lines', 0)} stdout, {output_summary.get('stderr_lines', 0)} stderr"
)
# Show prompt detection info
detector = get_global_detector()
@@ -182,6 +208,7 @@ def show_session_status(args):
print(f"Current state: {session_info['current_state']}")
print(f"Is waiting for input: {session_info['is_waiting']}")
def list_waiting_sessions(args=None):
"""List sessions that appear to be waiting for input."""
sessions = list_active_sessions()
@@ -193,14 +220,16 @@ def list_waiting_sessions(args=None):
waiting_sessions.append(session_name)
if not waiting_sessions:
print(f"{Colors.GREEN}No sessions are currently waiting for input.{Colors.RESET}")
print(
f"{Colors.GREEN}No sessions are currently waiting for input.{Colors.RESET}"
)
return
print(f"{Colors.BOLD}Sessions waiting for input:{Colors.RESET}")
for session_name in waiting_sessions:
status = get_session_status(session_name)
if status:
process_type = status.get('metadata', {}).get('process_type', 'unknown')
process_type = status.get("metadata", {}).get("process_type", "unknown")
print(f" {Colors.CYAN}{session_name}{Colors.RESET} ({process_type})")
# Show suggestions
@@ -208,17 +237,20 @@ def list_waiting_sessions(args=None):
if session_info:
suggestions = detector.get_response_suggestions({}, process_type)
if suggestions:
print(f" Suggested inputs: {', '.join(suggestions[:3])}") # Show first 3
print(
f" Suggested inputs: {', '.join(suggestions[:3])}"
) # Show first 3
print()
# Command registry for the multiplexer commands
MULTIPLEXER_COMMANDS = {
'show_sessions': show_sessions,
'attach_session': attach_session,
'detach_session': detach_session,
'kill_session': kill_session,
'send_command': send_command,
'show_session_log': show_session_log,
'show_session_status': show_session_status,
'list_waiting_sessions': list_waiting_sessions,
}
"show_sessions": show_sessions,
"attach_session": attach_session,
"detach_session": detach_session,
"kill_session": kill_session,
"send_command": send_command,
"show_session_log": show_session_log,
"show_session_status": show_session_status,
"list_waiting_sessions": list_waiting_sessions,
}