feat(prax): introspection standard compliance + monitor Phase 1 polling fallback
Co-Authored-By: @prax <prax@aipass>
This commit is contained in:
@@ -13,6 +13,13 @@
|
||||
"subject": "Seedgo log_structure standard update for hierarchical placement",
|
||||
"date_closed": "2026-03-09",
|
||||
"location": "prax"
|
||||
},
|
||||
{
|
||||
"plan_id": "FPLAN-0039",
|
||||
"type": "FPLAN",
|
||||
"subject": "Dashboard Pipeline — Full Lifecycle",
|
||||
"date_closed": "2026-03-18",
|
||||
"location": "prax"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -85,16 +85,16 @@ prax/
|
||||
│ ├── prax.py # Entry point (CLI)
|
||||
│ ├── modules/
|
||||
│ │ ├── logger.py # SystemLogger (public API)
|
||||
│ │ ├── monitor_module.py # Mission Control
|
||||
│ │ ├── agent_status_module.py # Agent status overview
|
||||
│ │ ├── monitor.py # Mission Control
|
||||
│ │ ├── agent_status.py # Agent status overview
|
||||
│ │ ├── dashboard.py # System dashboard
|
||||
│ │ ├── discover_module.py # Module discovery
|
||||
│ │ ├── init_module.py # Logging system initialization
|
||||
│ │ ├── log_audit_module.py # Log file audit
|
||||
│ │ ├── run_module.py # Continuous logging mode
|
||||
│ │ ├── shutdown_module.py # Logging system shutdown
|
||||
│ │ ├── status_module.py # System status / STATUS sync
|
||||
│ │ └── terminal_module.py # Terminal output toggle
|
||||
│ │ ├── discover.py # Module discovery
|
||||
│ │ ├── init_prax.py # Logging system initialization
|
||||
│ │ ├── log_audit.py # Log file audit
|
||||
│ │ ├── run.py # Continuous logging mode
|
||||
│ │ ├── shutdown.py # Logging system shutdown
|
||||
│ │ ├── status.py # System status / STATUS sync
|
||||
│ │ └── terminal.py # Terminal output toggle
|
||||
│ └── handlers/
|
||||
│ ├── central/ # Central file reader
|
||||
│ ├── config/ # Configuration loading
|
||||
|
||||
@@ -74,18 +74,35 @@ def get_system_logs_dir() -> Path:
|
||||
def get_module_logs_dir(module_name: str) -> Path:
|
||||
"""Get the branch-root logs directory for a module.
|
||||
|
||||
Returns ECOSYSTEM_ROOT / module_name / "logs", creating it if needed.
|
||||
Checks ECOSYSTEM_ROOT (src/aipass/) first, then SRC_ROOT (src/) for
|
||||
branches that live outside the aipass namespace (e.g., commons).
|
||||
This is the primary local log directory resolver for the two-tier
|
||||
model (system_logs/ for central aggregation + branch-root logs/
|
||||
for local debugging).
|
||||
|
||||
Args:
|
||||
module_name: Module name (e.g., "flow", "prax", "trigger")
|
||||
module_name: Module name (e.g., "flow", "prax", "commons")
|
||||
|
||||
Returns:
|
||||
Path to the module's branch-root logs directory
|
||||
"""
|
||||
logs_dir = ECOSYSTEM_ROOT / module_name / "logs"
|
||||
# Standard: src/aipass/{module}/logs
|
||||
branch_dir = ECOSYSTEM_ROOT / module_name
|
||||
if branch_dir.exists():
|
||||
logs_dir = branch_dir / "logs"
|
||||
logs_dir.mkdir(parents=True, exist_ok=True)
|
||||
return logs_dir
|
||||
|
||||
# Fallback: src/{module}/logs for branches outside aipass namespace
|
||||
src_root = ECOSYSTEM_ROOT.parent
|
||||
alt_branch_dir = src_root / module_name
|
||||
if alt_branch_dir.exists():
|
||||
logs_dir = alt_branch_dir / "logs"
|
||||
logs_dir.mkdir(parents=True, exist_ok=True)
|
||||
return logs_dir
|
||||
|
||||
# Default: create under ECOSYSTEM_ROOT (original behavior for new branches)
|
||||
logs_dir = branch_dir / "logs"
|
||||
logs_dir.mkdir(parents=True, exist_ok=True)
|
||||
return logs_dir
|
||||
|
||||
|
||||
@@ -78,17 +78,20 @@ def get_calling_module_path() -> Optional[str]:
|
||||
del frame
|
||||
|
||||
_AIPASS_PKG_ROOT = Path(__file__).resolve().parents[4] # logging/ → handlers/ → apps/ → prax/ → aipass/
|
||||
_SRC_ROOT = _AIPASS_PKG_ROOT.parent # aipass/ → src/ (contains branches outside aipass namespace)
|
||||
|
||||
def detect_branch_from_path(module_path: str) -> Optional[str]:
|
||||
"""Detect branch name from module file path
|
||||
|
||||
The package structure is: .../src/aipass/{module}/apps/...
|
||||
Resolves relative to the aipass package root found via __file__.
|
||||
Also handles branches outside src/aipass/ (e.g., src/commons/).
|
||||
|
||||
Examples:
|
||||
.../src/aipass/flow/apps/module.py → "flow"
|
||||
.../src/aipass/prax/apps/module.py → "prax"
|
||||
.../src/aipass/drone/apps/branch.py → "drone"
|
||||
.../src/commons/apps/module.py → "commons"
|
||||
|
||||
Returns:
|
||||
Module/branch name (e.g., "flow") or None
|
||||
@@ -96,8 +99,10 @@ def detect_branch_from_path(module_path: str) -> Optional[str]:
|
||||
if not module_path:
|
||||
return None
|
||||
|
||||
path = Path(module_path).resolve()
|
||||
|
||||
# Primary: src/aipass/{branch}/...
|
||||
try:
|
||||
path = Path(module_path).resolve()
|
||||
relative = path.relative_to(_AIPASS_PKG_ROOT)
|
||||
# relative is like: flow/apps/module.py → parts[0] = "flow"
|
||||
if len(relative.parts) >= 2:
|
||||
@@ -107,4 +112,14 @@ def detect_branch_from_path(module_path: str) -> Optional[str]:
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Fallback: src/{branch}/... for branches outside src/aipass/ (e.g., commons)
|
||||
try:
|
||||
relative = path.relative_to(_SRC_ROOT)
|
||||
if len(relative.parts) >= 2 and relative.parts[0] != "aipass":
|
||||
branch = relative.parts[0]
|
||||
json_handler.log_operation("introspection_resolved", {"module_path": module_path, "branch": branch, "outside_aipass": True})
|
||||
return branch
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
@@ -104,7 +104,7 @@ def setup_individual_logger(module_name: str) -> logging.Logger:
|
||||
if branch_path:
|
||||
branch_name = Path(branch_path).name
|
||||
else:
|
||||
branch_name = "prax" # Fallback to prax if no branch detected
|
||||
branch_name = "unknown_branch" # Visible fallback — never silently route to prax
|
||||
|
||||
# Create formatter (shared by all handlers)
|
||||
formatter = logging.Formatter(
|
||||
|
||||
@@ -20,7 +20,7 @@ Flow:
|
||||
5. Include branch attribution in all events
|
||||
|
||||
Thread Safety:
|
||||
- Designed to run in monitor_module.py's file watcher thread
|
||||
- Designed to run in monitor.py's file watcher thread
|
||||
- Uses MonitoringQueue's thread-safe enqueue
|
||||
- Watchdog observers run in their own threads
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Watchdog FileSystemEventHandler that processes filesystem events and:
|
||||
2. Fires trigger events for cross-module integration
|
||||
3. Parses Claude Code JSONL sessions for agent activity tracking
|
||||
|
||||
Extracted from monitor_module.py to maintain 3-layer architecture:
|
||||
Extracted from monitor.py to maintain 3-layer architecture:
|
||||
module (orchestration) -> handler (implementation)
|
||||
"""
|
||||
|
||||
|
||||
@@ -493,15 +493,16 @@ class LogFileWatcher(FileSystemEventHandler):
|
||||
logger.info(f"Error replaying {log_file}: {e}")
|
||||
|
||||
|
||||
def start_log_watcher(event_queue: MonitoringQueue) -> Any:
|
||||
def start_log_watcher(event_queue: MonitoringQueue, use_polling: bool = False) -> Any:
|
||||
"""
|
||||
Start watching log files and pushing events to queue.
|
||||
|
||||
Args:
|
||||
event_queue: MonitoringQueue instance for event delivery
|
||||
use_polling: If True, use PollingObserver instead of native inotify
|
||||
|
||||
Returns:
|
||||
Observer instance (caller must keep alive and call .stop() on shutdown)
|
||||
Observer instance
|
||||
"""
|
||||
global _log_observer
|
||||
|
||||
@@ -513,18 +514,28 @@ def start_log_watcher(event_queue: MonitoringQueue) -> Any:
|
||||
# Create watcher instance
|
||||
watcher = LogFileWatcher(event_queue)
|
||||
|
||||
# Soft start: seek to end of all logs, only show NEW activity
|
||||
# Replay recent lines for startup context (before seeking to EOF)
|
||||
watcher.replay_recent(num_lines=2)
|
||||
|
||||
# Soft start: seek to end of all logs, only show NEW activity after this
|
||||
watcher.initialize_positions()
|
||||
|
||||
# Create and start observer
|
||||
observer = WatchdogObserver()
|
||||
# Create observer — polling fallback when inotify unavailable
|
||||
if use_polling:
|
||||
from watchdog.observers.polling import PollingObserver
|
||||
observer = PollingObserver(timeout=1)
|
||||
logger.info("Log watcher using polling observer (1s interval)")
|
||||
else:
|
||||
observer = WatchdogObserver()
|
||||
|
||||
observer.schedule(watcher, str(get_system_logs_dir()), recursive=False)
|
||||
observer.start()
|
||||
|
||||
_log_observer = observer
|
||||
|
||||
json_handler.log_operation("log_watcher_started", {"log_dir": str(get_system_logs_dir())})
|
||||
logger.info(f"Log watcher started, monitoring: {get_system_logs_dir()}")
|
||||
mode = "polling" if use_polling else "inotify"
|
||||
json_handler.log_operation("log_watcher_started", {"log_dir": str(get_system_logs_dir()), "mode": mode})
|
||||
logger.info(f"Log watcher started ({mode}), monitoring: {get_system_logs_dir()}")
|
||||
|
||||
return observer
|
||||
|
||||
|
||||
+1
-5
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: agent_status_module.py
|
||||
# Name: agent_status.py
|
||||
# Description: PRAX Agent Status Push Command
|
||||
# Version: 0.1.0
|
||||
# Created: 2026-02-25
|
||||
@@ -73,10 +73,6 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
if command != 'agent-status-push':
|
||||
return False
|
||||
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
from aipass.prax.apps.handlers.dashboard.agent_status_writer import (
|
||||
build_agent_status_section,
|
||||
push_agent_status_dashboard,
|
||||
@@ -12,7 +12,7 @@ Dashboard Section Utilities
|
||||
Provides utilities for services to update their sections in branch
|
||||
DASHBOARD.local.json files. Each service manages only its own section.
|
||||
|
||||
Run directly or via: python3 apps/modules/dashboard.py
|
||||
Run via: drone @prax dashboard
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
@@ -162,7 +162,7 @@ def print_introspection():
|
||||
for section in DASHBOARD_TEMPLATE["sections"]:
|
||||
console.print(f" - {section}")
|
||||
console.print()
|
||||
console.print("[dim]Run 'python3 dashboard.py --help' for usage[/dim]")
|
||||
console.print("[dim]Run 'drone @prax dashboard --help' for usage[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -465,6 +465,10 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
if args[0] in ('--help', '-h', 'help'):
|
||||
print_help()
|
||||
return True
|
||||
|
||||
subcmd = args[0]
|
||||
json_handler.log_operation("dashboard_command", {"subcommand": subcmd})
|
||||
|
||||
|
||||
+43
-23
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: discover_module.py
|
||||
# Name: discover.py
|
||||
# Description: PRAX Discover Command
|
||||
# Version: 1.0.0
|
||||
# Created: 2025-11-15
|
||||
@@ -15,28 +15,33 @@ Implements the 'discover' command using handle_command interface.
|
||||
import sys
|
||||
from typing import List
|
||||
|
||||
from aipass.cli.apps.modules import console
|
||||
from aipass.cli.apps.modules import console, error
|
||||
from aipass.prax.apps.handlers.discovery.scanner import discover_python_modules
|
||||
from aipass.prax.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def print_help():
|
||||
"""Display module help and connected handlers"""
|
||||
"""Drone-compliant help output - command syntax and examples"""
|
||||
console.print()
|
||||
console.print("[bold cyan]PRAX Discover Module[/bold cyan]")
|
||||
console.print()
|
||||
console.print("[yellow]Connected Handlers:[/yellow]")
|
||||
console.print("[bold cyan]PRAX Discover - Scan Python Modules[/bold cyan]")
|
||||
console.print()
|
||||
|
||||
console.print(" [cyan]prax/modules/[/cyan]")
|
||||
console.print(" [dim]- logger.py[/dim] (system_logger)")
|
||||
console.print("[yellow]Purpose:[/yellow]")
|
||||
console.print(" Scan and register Python modules in the AIPass ecosystem")
|
||||
console.print()
|
||||
|
||||
console.print(" [cyan]prax/handlers/discovery/[/cyan]")
|
||||
console.print(" [dim]- scanner.py[/dim] (discover_python_modules)")
|
||||
console.print("[yellow]Usage:[/yellow]")
|
||||
console.print(" drone @prax discover scan")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'python3 discover_module.py --help' for usage[/dim]")
|
||||
console.print("[yellow]Subcommands:[/yellow]")
|
||||
console.print(" scan Discover and register Python modules")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Examples:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [dim]# Discover Python modules[/dim]")
|
||||
console.print(" $ drone @prax discover scan")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -58,24 +63,39 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
json_handler.log_operation("discover_command_executed", {"command": command})
|
||||
console.print("🔍 Discovering Python modules...")
|
||||
modules = discover_python_modules()
|
||||
console.print(f"✅ Discovered {len(modules)} modules")
|
||||
if args[0] in ('--help', '-h', 'help'):
|
||||
print_help()
|
||||
return True
|
||||
|
||||
if args[0] == 'scan':
|
||||
json_handler.log_operation("discover_command_executed", {"command": command})
|
||||
console.print("🔍 Discovering Python modules...")
|
||||
modules = discover_python_modules()
|
||||
console.print(f"✅ Discovered {len(modules)} modules")
|
||||
return True
|
||||
|
||||
error(f"Unknown discover subcommand: {args[0]}")
|
||||
print_help()
|
||||
return True
|
||||
|
||||
|
||||
def print_introspection():
|
||||
"""Display module introspection info."""
|
||||
"""Display module introspection - shows connected handlers"""
|
||||
console.print()
|
||||
console.print("discover_module Module")
|
||||
console.print("Implements the 'discover' command to scan and register Python modules")
|
||||
console.print("[bold cyan]PRAX Discover Module[/bold cyan]")
|
||||
console.print()
|
||||
console.print("Connected Handlers:")
|
||||
console.print(" modules/")
|
||||
console.print(" - logger.py (system_logger — auto-routing logger for module log files)")
|
||||
console.print(" handlers/discovery/")
|
||||
console.print(" - scanner.py (discover_python_modules — scans filesystem for Python modules)")
|
||||
console.print("[yellow]Connected Handlers:[/yellow]")
|
||||
console.print()
|
||||
|
||||
console.print(" [cyan]prax/modules/[/cyan]")
|
||||
console.print(" [dim]- logger.py[/dim] (system_logger)")
|
||||
console.print()
|
||||
|
||||
console.print(" [cyan]prax/handlers/discovery/[/cyan]")
|
||||
console.print(" [dim]- scanner.py[/dim] (discover_python_modules)")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'drone @prax discover --help' for usage[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
+30
-16
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: init_module.py
|
||||
# Name: init_prax.py
|
||||
# Description: PRAX Init Command
|
||||
# Version: 1.0.0
|
||||
# Created: 2025-11-15
|
||||
@@ -32,7 +32,7 @@ def print_introspection():
|
||||
console.print(" [dim]- logger.py[/dim] (initialize_logging_system, system_logger)")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'python3 init_module.py --help' for usage[/dim]")
|
||||
console.print("[dim]Run 'drone @prax init --help' for usage[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -46,13 +46,18 @@ def print_help():
|
||||
console.print(" Initialize the PRAX logging system for monitoring AIPass operations")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Usage Examples:[/yellow]")
|
||||
console.print("[yellow]Usage:[/yellow]")
|
||||
console.print(" drone @prax init start")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Subcommands:[/yellow]")
|
||||
console.print(" start Initialize the PRAX logging system")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Examples:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [dim]# Initialize logging system[/dim]")
|
||||
console.print(" $ prax init")
|
||||
console.print()
|
||||
console.print(" [dim]# Standalone execution[/dim]")
|
||||
console.print(" $ python3 init_module.py")
|
||||
console.print(" $ drone @prax init start")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -74,17 +79,26 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
try:
|
||||
json_handler.log_operation("init_command_executed", {"command": command})
|
||||
console.print("🚀 Initializing PRAX logging system...")
|
||||
initialize_logging_system()
|
||||
console.print("✅ PRAX logging system initialized")
|
||||
if args[0] in ('--help', '-h', 'help'):
|
||||
print_help()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in init command: {e}")
|
||||
error(str(e))
|
||||
return True
|
||||
if args[0] == 'start':
|
||||
try:
|
||||
json_handler.log_operation("init_command_executed", {"command": command})
|
||||
console.print("🚀 Initializing PRAX logging system...")
|
||||
initialize_logging_system()
|
||||
console.print("✅ PRAX logging system initialized")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in init command: {e}")
|
||||
error(str(e))
|
||||
return True
|
||||
|
||||
error(f"Unknown init subcommand: {args[0]}")
|
||||
print_help()
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
+24
-11
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: log_audit_module.py
|
||||
# Name: log_audit.py
|
||||
# Description: PRAX Log Audit Command
|
||||
# Version: 0.1.0
|
||||
# Created: 2026-02-26
|
||||
@@ -37,7 +37,7 @@ def print_introspection():
|
||||
console.print(" [dim]- log_watchdog.py (scan_log_files, enforce_log_limits, log_health_summary)[/dim]")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'drone @prax log-audit' for status, 'drone @prax log-audit enforce' to truncate[/dim]")
|
||||
console.print("[dim]Run 'drone @prax log-audit --help' for usage[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -51,10 +51,15 @@ def print_help():
|
||||
console.print(" Scan system_logs/ for oversized files and enforce rotation limits")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Subcommands:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [cyan]audit[/cyan] Show log health summary + any oversized files")
|
||||
console.print(" [cyan]enforce[/cyan] Truncate all oversized files to 1000 lines")
|
||||
console.print()
|
||||
console.print("[yellow]Usage:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [dim]# Show log health summary + any oversized files[/dim]")
|
||||
console.print(" $ drone @prax log-audit")
|
||||
console.print(" $ drone @prax log-audit audit")
|
||||
console.print()
|
||||
console.print(" [dim]# Truncate all oversized files to 1000 lines[/dim]")
|
||||
console.print(" $ drone @prax log-audit enforce")
|
||||
@@ -108,15 +113,25 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
if args[0] in ('--help', '-h', 'help'):
|
||||
print_help()
|
||||
return True
|
||||
|
||||
from aipass.prax.apps.handlers.logging.log_watchdog import (
|
||||
scan_log_files,
|
||||
enforce_log_limits,
|
||||
log_health_summary,
|
||||
)
|
||||
|
||||
json_handler.log_operation("log_audit_executed", {"mode": args[0] if args else "audit"})
|
||||
subcmd = args[0]
|
||||
json_handler.log_operation("log_audit_executed", {"mode": subcmd})
|
||||
|
||||
if args and args[0] == 'enforce':
|
||||
if subcmd == 'audit':
|
||||
files = scan_log_files()
|
||||
summary = log_health_summary()
|
||||
_display_audit(files, summary)
|
||||
return True
|
||||
elif subcmd == 'enforce':
|
||||
console.print("\n[bold cyan]Enforcing log limits...[/bold cyan]")
|
||||
actions = enforce_log_limits()
|
||||
|
||||
@@ -134,12 +149,10 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
console.print()
|
||||
logger.info("[log-audit] Enforced limits on %d files", len(actions))
|
||||
return True
|
||||
|
||||
# Default: audit mode
|
||||
files = scan_log_files()
|
||||
summary = log_health_summary()
|
||||
_display_audit(files, summary)
|
||||
return True
|
||||
else:
|
||||
error(f"Unknown log-audit subcommand: {subcmd}")
|
||||
print_help()
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
+152
-28
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: monitor_module.py
|
||||
# Name: monitor.py
|
||||
# Description: Unified Monitoring Module
|
||||
# Version: 0.3.0
|
||||
# Created: 2025-11-23
|
||||
@@ -22,9 +22,9 @@ Purpose:
|
||||
Enables multi-agent workflow visibility and coordination.
|
||||
|
||||
Usage:
|
||||
prax monitor # Monitor all branches (quiet mode)
|
||||
prax monitor all # Explicit all-branches monitoring
|
||||
prax monitor seed,cli # Monitor specific branches
|
||||
drone @prax monitor # Show introspection
|
||||
drone @prax monitor run # Monitor all branches
|
||||
drone @prax monitor run seed,cli # Monitor specific branches
|
||||
|
||||
Interactive Commands:
|
||||
help # Show available commands
|
||||
@@ -50,6 +50,7 @@ import sys
|
||||
import argparse
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
@@ -68,6 +69,7 @@ from aipass.prax.apps.handlers.monitoring import (
|
||||
MonitoringQueue, # event_queue.py
|
||||
ModuleTracker, # module_tracker.py
|
||||
)
|
||||
from aipass.prax.apps.handlers.monitoring.event_queue import MonitoringEvent
|
||||
# NOTE: FileSystemEventHandler implementation lives in:
|
||||
# aipass.prax.apps.handlers.monitoring.filesystem_handler.MonitoringFileHandler
|
||||
# It handles trigger events for file_created/file_deleted/file_modified/file_moved
|
||||
@@ -202,10 +204,29 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
if command != 'monitor':
|
||||
return False
|
||||
|
||||
# Introspection gate — bare command shows module info
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
# Help intercept
|
||||
if args[0] in ('--help', '-h', 'help'):
|
||||
print_help()
|
||||
return True
|
||||
|
||||
# Subcommand routing
|
||||
subcmd = args[0]
|
||||
if subcmd == 'run':
|
||||
return _run_monitor(args[1:])
|
||||
|
||||
# Unknown subcommand
|
||||
error(f"Unknown monitor subcommand: {subcmd}")
|
||||
print_help()
|
||||
return True
|
||||
|
||||
|
||||
def _run_monitor(args: List[str]) -> bool:
|
||||
"""Launch Mission Control live monitoring."""
|
||||
global _monitoring_active, _event_queue, _module_tracker
|
||||
global _display_thread, _file_watcher_thread, _log_watcher_thread
|
||||
|
||||
@@ -304,6 +325,47 @@ def _display_worker():
|
||||
print_event(event.event_type, event.branch, event.message, event.level, pid=branch_pid)
|
||||
|
||||
|
||||
def _get_watch_directories(repo_root: Path) -> list[tuple[Path, bool]]:
|
||||
"""Get targeted directories to watch instead of entire repo root.
|
||||
|
||||
Returns (path, recursive) tuples. Watches apps/ recursively for code,
|
||||
branch roots non-recursively for STATUS/README, and .trinity/ for identity.
|
||||
|
||||
Some branches (backup, memory) have 10,000+ dirs in data stores.
|
||||
Watching only apps/ keeps inotify count under ~800.
|
||||
"""
|
||||
dirs: list[tuple[Path, bool]] = []
|
||||
|
||||
# Load branch paths from registry
|
||||
registry_path = repo_root / "AIPASS_REGISTRY.json"
|
||||
if registry_path.exists():
|
||||
try:
|
||||
data = _json.loads(registry_path.read_text(encoding="utf-8"))
|
||||
for branch in data.get("branches", []):
|
||||
branch_path = repo_root / branch.get("path", "")
|
||||
if not branch_path.exists():
|
||||
continue
|
||||
# apps/ recursive — source code changes
|
||||
apps_dir = branch_path / "apps"
|
||||
if apps_dir.exists():
|
||||
dirs.append((apps_dir, True))
|
||||
# Branch root non-recursive — STATUS.local.md, README.md
|
||||
dirs.append((branch_path, False))
|
||||
# .trinity/ non-recursive — identity files
|
||||
trinity_dir = branch_path / ".trinity"
|
||||
if trinity_dir.exists():
|
||||
dirs.append((trinity_dir, False))
|
||||
except (ValueError, OSError) as e:
|
||||
logger.warning(f"[monitor] Failed to read registry: {e}")
|
||||
|
||||
# Watch Claude Code project sessions for agent activity tracking
|
||||
claude_projects = Path.home() / ".claude" / "projects"
|
||||
if claude_projects.exists():
|
||||
dirs.append((claude_projects, True))
|
||||
|
||||
return dirs
|
||||
|
||||
|
||||
def _file_watcher_worker():
|
||||
"""File watcher thread - watches filesystem changes and pushes to queue"""
|
||||
global _monitoring_active, _event_queue
|
||||
@@ -311,24 +373,64 @@ def _file_watcher_worker():
|
||||
from watchdog.observers import Observer
|
||||
from aipass.prax.apps.handlers.monitoring.filesystem_handler import MonitoringFileHandler
|
||||
|
||||
# Files whose modification indicates a command is running (python3 direct calls)
|
||||
# Maps filename -> command description. Used to emit command separators from file events.
|
||||
COMMAND_INDICATOR_FILES = {
|
||||
'standards_audit_log.json': 'seed audit',
|
||||
'standards_checklist_log.json': 'seed checklist',
|
||||
}
|
||||
|
||||
# Create observer and start watching
|
||||
# Watch from repo root (covers all modules)
|
||||
from aipass.prax.apps.handlers.config.load import _find_repo_root
|
||||
observer = Observer()
|
||||
handler = MonitoringFileHandler(
|
||||
event_queue=_event_queue,
|
||||
command_indicator_files=COMMAND_INDICATOR_FILES,
|
||||
)
|
||||
watch_dir = _find_repo_root()
|
||||
observer.schedule(handler, str(watch_dir), recursive=True)
|
||||
observer.start()
|
||||
|
||||
from aipass.prax.apps.handlers.config.load import _find_repo_root
|
||||
repo_root = _find_repo_root()
|
||||
watch_dirs = _get_watch_directories(repo_root)
|
||||
|
||||
if not watch_dirs:
|
||||
logger.error("[monitor] No watch directories found — file watcher disabled")
|
||||
if _event_queue:
|
||||
_event_queue.enqueue(MonitoringEvent(
|
||||
priority=2, event_type='log', branch='PRAX',
|
||||
action='warning', level='warning', timestamp=datetime.now(),
|
||||
message="File watcher: no watch directories found — file events disabled"
|
||||
))
|
||||
return
|
||||
|
||||
observer = Observer()
|
||||
for watch_dir, recursive in watch_dirs:
|
||||
observer.schedule(handler, str(watch_dir), recursive=recursive)
|
||||
|
||||
logger.info(f"[monitor] File watcher: {len(watch_dirs)} watches scheduled")
|
||||
|
||||
try:
|
||||
observer.start()
|
||||
except OSError as e:
|
||||
logger.warning(f"[monitor] inotify unavailable: {e} — switching to polling")
|
||||
if _event_queue:
|
||||
_event_queue.enqueue(MonitoringEvent(
|
||||
priority=2, event_type='log', branch='PRAX',
|
||||
action='warning', level='warning', timestamp=datetime.now(),
|
||||
message="File watcher: inotify unavailable — using polling fallback (slower)"
|
||||
))
|
||||
|
||||
# Fallback to PollingObserver
|
||||
try:
|
||||
from watchdog.observers.polling import PollingObserver
|
||||
observer = PollingObserver(timeout=2)
|
||||
for watch_dir, recursive in watch_dirs:
|
||||
observer.schedule(handler, str(watch_dir), recursive=recursive)
|
||||
observer.start()
|
||||
logger.info("[monitor] File watcher: polling fallback active")
|
||||
except Exception as e2:
|
||||
logger.error(f"[monitor] Polling fallback also failed: {e2}")
|
||||
if _event_queue:
|
||||
_event_queue.enqueue(MonitoringEvent(
|
||||
priority=1, event_type='log', branch='PRAX',
|
||||
action='error', level='error', timestamp=datetime.now(),
|
||||
message="File watcher: completely unavailable — no file events"
|
||||
))
|
||||
return
|
||||
|
||||
try:
|
||||
while _monitoring_active:
|
||||
@@ -344,12 +446,31 @@ def _log_watcher_worker():
|
||||
|
||||
from aipass.prax.apps.handlers.monitoring.log_watcher import start_log_watcher, stop_log_watcher
|
||||
|
||||
# Start the proper log watcher (has command detection, branch detection, message parsing)
|
||||
# Guard against None - should never happen since we initialize before starting threads
|
||||
if _event_queue is None:
|
||||
logger.error("[monitor] Event queue not initialized for log watcher")
|
||||
return
|
||||
_observer = start_log_watcher(_event_queue)
|
||||
|
||||
try:
|
||||
start_log_watcher(_event_queue)
|
||||
except OSError as e:
|
||||
logger.warning(f"[monitor] Log watcher inotify failed: {e} — switching to polling")
|
||||
if _event_queue:
|
||||
_event_queue.enqueue(MonitoringEvent(
|
||||
priority=2, event_type='log', branch='PRAX',
|
||||
action='warning', level='warning', timestamp=datetime.now(),
|
||||
message="Log watcher: inotify unavailable — using polling fallback (slower)"
|
||||
))
|
||||
try:
|
||||
start_log_watcher(_event_queue, use_polling=True)
|
||||
except Exception as e2:
|
||||
logger.error(f"[monitor] Log watcher polling fallback failed: {e2}")
|
||||
if _event_queue:
|
||||
_event_queue.enqueue(MonitoringEvent(
|
||||
priority=1, event_type='log', branch='PRAX',
|
||||
action='error', level='error', timestamp=datetime.now(),
|
||||
message="Log watcher: completely unavailable — no log events"
|
||||
))
|
||||
return
|
||||
|
||||
try:
|
||||
while _monitoring_active:
|
||||
@@ -383,7 +504,7 @@ def _interactive_loop():
|
||||
if not user_input:
|
||||
continue
|
||||
|
||||
cmd, cmd_args = parse_command(user_input)
|
||||
cmd, _cmd_args = parse_command(user_input)
|
||||
if not cmd:
|
||||
continue
|
||||
|
||||
@@ -460,7 +581,7 @@ def print_introspection():
|
||||
console.print(" [green]STATUS: Active - watches *.log files for new entries[/green]")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'python3 monitor_module.py --help' for usage[/dim]")
|
||||
console.print("[dim]Run 'drone @prax monitor --help' for usage[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -476,15 +597,21 @@ def print_help():
|
||||
|
||||
console.print("[yellow]Commands:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [cyan]monitor[/cyan]")
|
||||
console.print(" Start monitoring all branches (quiet mode)")
|
||||
console.print(" [cyan]drone @prax monitor[/cyan]")
|
||||
console.print(" Show module introspection")
|
||||
console.print()
|
||||
console.print(" [cyan]monitor all[/cyan]")
|
||||
console.print(" [cyan]drone @prax monitor run[/cyan]")
|
||||
console.print(" Start monitoring all branches")
|
||||
console.print()
|
||||
console.print(" [cyan]drone @prax monitor run all[/cyan]")
|
||||
console.print(" Explicit all-branches monitoring")
|
||||
console.print()
|
||||
console.print(" [cyan]monitor [branches][/cyan]")
|
||||
console.print(" [cyan]drone @prax monitor run [branches][/cyan]")
|
||||
console.print(" Monitor specific branches (comma-separated)")
|
||||
console.print(" Example: monitor seed,cli,flow")
|
||||
console.print(" Example: drone @prax monitor run seed,cli,flow")
|
||||
console.print()
|
||||
console.print(" [cyan]drone @prax monitor --help[/cyan]")
|
||||
console.print(" Show this help")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Interactive Mode Commands:[/yellow]")
|
||||
@@ -498,13 +625,10 @@ def print_help():
|
||||
console.print("[yellow]Examples:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [dim]# Monitor all branches[/dim]")
|
||||
console.print(" $ prax monitor")
|
||||
console.print(" $ drone @prax monitor run")
|
||||
console.print()
|
||||
console.print(" [dim]# Monitor specific branches[/dim]")
|
||||
console.print(" $ prax monitor seed,cli,flow")
|
||||
console.print()
|
||||
console.print(" [dim]# Standalone execution[/dim]")
|
||||
console.print(" $ python3 monitor_module.py")
|
||||
console.print(" $ drone @prax monitor run seed,cli,flow")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: run_module.py
|
||||
# Name: run.py
|
||||
# Description: PRAX Run Command
|
||||
# Version: 1.0.0
|
||||
# Created: 2025-11-15
|
||||
@@ -16,23 +16,32 @@ import sys
|
||||
from typing import List
|
||||
|
||||
from aipass.prax.apps.modules.logger import start_continuous_logging
|
||||
from aipass.cli.apps.modules import console
|
||||
from aipass.cli.apps.modules import console, error
|
||||
from aipass.prax.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def print_help():
|
||||
"""Display module help and connected handlers"""
|
||||
"""Drone-compliant help output - command syntax and examples"""
|
||||
console.print()
|
||||
console.print("[bold cyan]PRAX Run Module[/bold cyan]")
|
||||
console.print()
|
||||
console.print("[yellow]Connected Handlers:[/yellow]")
|
||||
console.print("[bold cyan]PRAX Run - Continuous Logging Mode[/bold cyan]")
|
||||
console.print()
|
||||
|
||||
console.print(" [cyan]prax/modules/[/cyan]")
|
||||
console.print(" [dim]- logger.py[/dim] (start_continuous_logging, system_logger)")
|
||||
console.print("[yellow]Purpose:[/yellow]")
|
||||
console.print(" Start PRAX continuous logging mode for monitoring AIPass operations")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'python3 run_module.py --help' for usage[/dim]")
|
||||
console.print("[yellow]Usage:[/yellow]")
|
||||
console.print(" drone @prax run start")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Subcommands:[/yellow]")
|
||||
console.print(" start Start continuous logging mode")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Examples:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [dim]# Start continuous logging[/dim]")
|
||||
console.print(" $ drone @prax run start")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -54,22 +63,34 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
json_handler.log_operation("run_command_executed", {"command": command})
|
||||
console.print("🚀 Starting PRAX continuous logging mode...")
|
||||
start_continuous_logging()
|
||||
if args[0] in ('--help', '-h', 'help'):
|
||||
print_help()
|
||||
return True
|
||||
|
||||
if args[0] == 'start':
|
||||
json_handler.log_operation("run_command_executed", {"command": command})
|
||||
console.print("🚀 Starting PRAX continuous logging mode...")
|
||||
start_continuous_logging()
|
||||
return True
|
||||
|
||||
error(f"Unknown run subcommand: {args[0]}")
|
||||
print_help()
|
||||
return True
|
||||
|
||||
|
||||
def print_introspection():
|
||||
"""Display module introspection info."""
|
||||
"""Display module introspection - shows connected handlers"""
|
||||
console.print()
|
||||
console.print("run_module Module")
|
||||
console.print("Implements the 'run' command to start PRAX continuous logging mode")
|
||||
console.print("[bold cyan]PRAX Run Module[/bold cyan]")
|
||||
console.print()
|
||||
console.print("Connected Handlers:")
|
||||
console.print(" modules/")
|
||||
console.print(" - logger.py (start_continuous_logging — starts background logging loop)")
|
||||
console.print(" - logger.py (system_logger — auto-routing logger for module log files)")
|
||||
console.print("[yellow]Connected Handlers:[/yellow]")
|
||||
console.print()
|
||||
|
||||
console.print(" [cyan]prax/modules/[/cyan]")
|
||||
console.print(" [dim]- logger.py[/dim] (start_continuous_logging, system_logger)")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'drone @prax run --help' for usage[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
+41
-20
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: shutdown_module.py
|
||||
# Name: shutdown.py
|
||||
# Description: PRAX Shutdown Command
|
||||
# Version: 1.0.0
|
||||
# Created: 2025-11-15
|
||||
@@ -16,23 +16,32 @@ import sys
|
||||
from typing import List
|
||||
|
||||
from aipass.prax.apps.modules.logger import shutdown_logging_system
|
||||
from aipass.cli.apps.modules import console
|
||||
from aipass.cli.apps.modules import console, error
|
||||
from aipass.prax.apps.handlers.json import json_handler
|
||||
|
||||
|
||||
def print_help():
|
||||
"""Display module help and connected handlers"""
|
||||
"""Drone-compliant help output - command syntax and examples"""
|
||||
console.print()
|
||||
console.print("[bold cyan]PRAX Shutdown Module[/bold cyan]")
|
||||
console.print()
|
||||
console.print("[yellow]Connected Handlers:[/yellow]")
|
||||
console.print("[bold cyan]PRAX Shutdown - Stop Logging System[/bold cyan]")
|
||||
console.print()
|
||||
|
||||
console.print(" [cyan]prax/modules/[/cyan]")
|
||||
console.print(" [dim]- logger.py[/dim] (shutdown_logging_system, system_logger)")
|
||||
console.print("[yellow]Purpose:[/yellow]")
|
||||
console.print(" Cleanly stop the PRAX logging system")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'python3 shutdown_module.py --help' for usage[/dim]")
|
||||
console.print("[yellow]Usage:[/yellow]")
|
||||
console.print(" drone @prax shutdown now")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Subcommands:[/yellow]")
|
||||
console.print(" now Shut down the PRAX logging system")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Examples:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [dim]# Shut down logging system[/dim]")
|
||||
console.print(" $ drone @prax shutdown now")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -54,23 +63,35 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
json_handler.log_operation("shutdown_command_executed", {"command": command})
|
||||
console.print("🛑 Shutting down PRAX logging system...")
|
||||
shutdown_logging_system()
|
||||
console.print("✅ PRAX logging system shutdown complete")
|
||||
if args[0] in ('--help', '-h', 'help'):
|
||||
print_help()
|
||||
return True
|
||||
|
||||
if args[0] == 'now':
|
||||
json_handler.log_operation("shutdown_command_executed", {"command": command})
|
||||
console.print("🛑 Shutting down PRAX logging system...")
|
||||
shutdown_logging_system()
|
||||
console.print("✅ PRAX logging system shutdown complete")
|
||||
return True
|
||||
|
||||
error(f"Unknown shutdown subcommand: {args[0]}")
|
||||
print_help()
|
||||
return True
|
||||
|
||||
|
||||
def print_introspection():
|
||||
"""Display module introspection info."""
|
||||
"""Display module introspection - shows connected handlers"""
|
||||
console.print()
|
||||
console.print("shutdown_module Module")
|
||||
console.print("Implements the 'shutdown' command to cleanly stop PRAX logging system")
|
||||
console.print("[bold cyan]PRAX Shutdown Module[/bold cyan]")
|
||||
console.print()
|
||||
console.print("Connected Handlers:")
|
||||
console.print(" modules/")
|
||||
console.print(" - logger.py (shutdown_logging_system — stops watcher, restores logger, logs shutdown)")
|
||||
console.print(" - logger.py (system_logger — auto-routing logger for module log files)")
|
||||
console.print("[yellow]Connected Handlers:[/yellow]")
|
||||
console.print()
|
||||
|
||||
console.print(" [cyan]prax/modules/[/cyan]")
|
||||
console.print(" [dim]- logger.py[/dim] (shutdown_logging_system, system_logger)")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'drone @prax shutdown --help' for usage[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
+2
-6
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: status_module.py
|
||||
# Name: status.py
|
||||
# Description: PRAX Status Command
|
||||
# Version: 1.1.0
|
||||
# Created: 2025-11-15
|
||||
@@ -45,10 +45,6 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
if command != 'status':
|
||||
return False
|
||||
|
||||
if not args:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
json_handler.log_operation("status_checked", {"subcommand": args[0] if args else "default"})
|
||||
|
||||
# --- sub-command routing ------------------------------------------------
|
||||
@@ -110,7 +106,7 @@ def _handle_sync() -> bool:
|
||||
def print_introspection():
|
||||
"""Display module introspection info."""
|
||||
console.print()
|
||||
console.print("status_module Module")
|
||||
console.print("status Module")
|
||||
console.print("Implements the 'status' command to display PRAX system status dashboard")
|
||||
console.print()
|
||||
console.print("Connected Handlers:")
|
||||
+8
-7
@@ -1,5 +1,5 @@
|
||||
# =================== AIPass ====================
|
||||
# Name: terminal_module.py
|
||||
# Name: terminal.py
|
||||
# Description: PRAX Terminal Command
|
||||
# Version: 1.1.0
|
||||
# Created: 2025-11-15
|
||||
@@ -36,7 +36,7 @@ def print_introspection():
|
||||
console.print(" [dim]- logger.py[/dim] (enable_terminal_output, disable_terminal_output, system_logger)")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Run 'python3 terminal_module.py --help' for usage[/dim]")
|
||||
console.print("[dim]Run 'drone @prax terminal --help' for usage[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -58,13 +58,10 @@ def print_help():
|
||||
console.print("[yellow]Usage Examples:[/yellow]")
|
||||
console.print()
|
||||
console.print(" [dim]# Enable terminal output[/dim]")
|
||||
console.print(" $ prax terminal enable")
|
||||
console.print(" $ drone @prax terminal enable")
|
||||
console.print()
|
||||
console.print(" [dim]# Disable terminal output[/dim]")
|
||||
console.print(" $ prax terminal disable")
|
||||
console.print()
|
||||
console.print(" [dim]# Standalone execution[/dim]")
|
||||
console.print(" $ python3 terminal_module.py enable")
|
||||
console.print(" $ drone @prax terminal disable")
|
||||
console.print()
|
||||
|
||||
console.print("[dim]Commands: enable, disable[/dim]")
|
||||
@@ -89,6 +86,10 @@ def handle_command(command: str, args: List[str]) -> bool:
|
||||
print_introspection()
|
||||
return True
|
||||
|
||||
if args[0] in ('--help', '-h', 'help'):
|
||||
print_help()
|
||||
return True
|
||||
|
||||
try:
|
||||
if args[0] not in ['enable', 'disable']:
|
||||
print_help()
|
||||
@@ -96,7 +96,37 @@ def print_introspection():
|
||||
console.print(f" [cyan]•[/cyan] {module_name}")
|
||||
|
||||
console.print()
|
||||
console.print("[dim]Run 'prax --help' for usage information[/dim]")
|
||||
console.print("[dim]Run 'drone @prax --help' for usage information[/dim]")
|
||||
console.print()
|
||||
|
||||
|
||||
def print_help():
|
||||
"""Rich-formatted top-level help for PRAX"""
|
||||
console.print()
|
||||
console.print("[bold cyan]PRAX - System-Wide Logging Infrastructure[/bold cyan]")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Commands:[/yellow]")
|
||||
console.print(" [cyan]monitor[/cyan] Mission Control - unified real-time monitoring")
|
||||
console.print(" [cyan]init[/cyan] Initialize PRAX logging system")
|
||||
console.print(" [cyan]status[/cyan] Show PRAX system status")
|
||||
console.print(" [cyan]run[/cyan] Start continuous logging mode")
|
||||
console.print(" [cyan]shutdown[/cyan] Shutdown PRAX logging system")
|
||||
console.print(" [cyan]discover[/cyan] Discover Python modules in ecosystem")
|
||||
console.print(" [cyan]terminal[/cyan] Enable/disable terminal output")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Flags:[/yellow]")
|
||||
console.print(" [cyan]--help, -h[/cyan] Show help information")
|
||||
console.print(" [cyan]--version, -V[/cyan] Show version")
|
||||
console.print(" [cyan]--verbose, -v[/cyan] Verbose output")
|
||||
console.print()
|
||||
|
||||
console.print("[yellow]Examples:[/yellow]")
|
||||
console.print(" $ drone @prax monitor")
|
||||
console.print(" $ drone @prax monitor run")
|
||||
console.print(" $ drone @prax status")
|
||||
console.print(" $ drone @prax terminal enable")
|
||||
console.print()
|
||||
|
||||
|
||||
@@ -135,6 +165,7 @@ def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='PRAX - System-Wide Logging Infrastructure',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
add_help=False, # We route --help to modules when a command is given
|
||||
epilog="""
|
||||
Available Commands:
|
||||
monitor Mission Control - unified real-time monitoring
|
||||
@@ -146,10 +177,10 @@ Available Commands:
|
||||
terminal Enable/disable terminal output (requires: enable|disable)
|
||||
|
||||
Examples:
|
||||
prax monitor
|
||||
prax init
|
||||
prax status
|
||||
prax terminal enable
|
||||
drone @prax monitor
|
||||
drone @prax init
|
||||
drone @prax status
|
||||
drone @prax terminal enable
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -163,14 +194,19 @@ Examples:
|
||||
nargs='*',
|
||||
help='Arguments for the command')
|
||||
|
||||
parser.add_argument('--help', '-h', action='store_true', dest='show_help',
|
||||
help='Show help information')
|
||||
parser.add_argument('--version', '-V', action='version', version='PRAX v2.0.0')
|
||||
parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
|
||||
|
||||
parsed_args, remaining = parser.parse_known_args()
|
||||
|
||||
# If no command provided, show introspection display
|
||||
# If no command provided, show introspection or top-level help
|
||||
if not parsed_args.command:
|
||||
print_introspection()
|
||||
if parsed_args.show_help:
|
||||
print_help()
|
||||
else:
|
||||
print_introspection()
|
||||
return 0
|
||||
|
||||
# Discover command modules
|
||||
@@ -184,6 +220,10 @@ Examples:
|
||||
# so subcommand handlers like dashboard can receive --all, --branch, etc.
|
||||
all_args = parsed_args.args + remaining
|
||||
|
||||
# Pass --help through to module handler (e.g. drone @prax monitor --help)
|
||||
if parsed_args.show_help:
|
||||
all_args = ['--help'] + all_args
|
||||
|
||||
# Route command to appropriate handler
|
||||
if route_command(parsed_args.command, all_args, handlers):
|
||||
return 0
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# dev.local.md - PRAX
|
||||
```
|
||||
Branch: /home/coder/workspace/AIPass/src/aipass/prax
|
||||
Created: 2026-03-07
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
-
|
||||
|
||||
---
|
||||
|
||||
## Todos
|
||||
|
||||
-
|
||||
Reference in New Issue
Block a user