diff --git a/src/aipass/memory/apps/memory.py b/src/aipass/memory/apps/memory.py index 917eab60..7b5a9bfa 100755 --- a/src/aipass/memory/apps/memory.py +++ b/src/aipass/memory/apps/memory.py @@ -107,13 +107,14 @@ def print_help(): table.add_column("Command", style="green") table.add_column("Description", style="dim") - # Core commands (only implemented ones) + # Core commands — only those with backing modules + table.add_row("rollover", "Show rollover module introspection") + table.add_row("rollover run", "Execute memory rollover") + table.add_row("rollover status", "Show rollover statistics") + table.add_row("rollover check", "Dry run — check what needs rollover") + table.add_row("rollover sync-lines", "Update line count metadata") table.add_row("search ", "Semantic search across all branch memories") - table.add_row("rollover", "Execute memory rollover for files exceeding limits") - table.add_row("status", "Show rollover statistics for all branches") - table.add_row("check", "Check which files need rollover (dry run)") table.add_row("watch", "Start memory watcher (auto-rollover on changes)") - table.add_row("sync-lines", "Update line count metadata for all branches") console.print(table) @@ -125,12 +126,12 @@ def print_help(): console.print() console.print(" [bold]Via Drone (recommended):[/bold]") console.print(" [dim]drone @memory search \"performance patterns\"[/dim]") - console.print(" [dim]drone @memory status[/dim]") - console.print(" [dim]drone @memory rollover[/dim]") + console.print(" [dim]drone @memory rollover status[/dim]") + console.print(" [dim]drone @memory rollover run[/dim]") console.print() console.print(" [bold]Direct execution:[/bold]") console.print(" [dim]python3 -m aipass.memory.apps.memory search \"query\"[/dim]") - console.print(" [dim]python3 -m aipass.memory.apps.memory rollover[/dim]") + console.print(" [dim]python3 -m aipass.memory.apps.memory rollover run[/dim]") console.print() console.print("-" * 70) console.print() @@ -158,7 +159,7 @@ def print_help(): console.print("-" * 70) console.print() - console.print("Commands: search, rollover, status, check, watch, sync-lines") + console.print("Commands: search, rollover [run|status|check|sync-lines], watch") console.print() diff --git a/src/aipass/memory/apps/modules/rollover.py b/src/aipass/memory/apps/modules/rollover.py index 61514224..b922e1af 100755 --- a/src/aipass/memory/apps/modules/rollover.py +++ b/src/aipass/memory/apps/modules/rollover.py @@ -1,9 +1,9 @@ # =================== AIPass ==================== # Name: rollover.py # Description: Rollover Orchestration Module -# Version: 0.5.0 +# Version: 0.6.0 # Created: 2025-11-16 -# Modified: 2026-03-08 +# Modified: 2026-03-15 # ============================================= """ @@ -21,6 +21,7 @@ Purpose: """ import sys +from pathlib import Path from typing import List from rich.panel import Panel @@ -45,15 +46,28 @@ from ..handlers.rollover.orchestrator import ( # COMMAND HANDLERS # ============================================================================= -def handle_command(command: str, args: List[str]) -> bool: # noqa: ARG001 - """ - Handle rollover commands +_SUBCOMMANDS = { + "run": "Execute rollover for files exceeding limits", + "status": "Show rollover statistics for all branches", + "check": "Check which files need rollover (dry run)", + "sync-lines": "Update line count metadata for all branches", +} - Commands supported: - - rollover: Execute rollover for triggered branches - - status: Show rollover statistics - - check: Check which branches need rollover - - sync-lines: Update line count metadata for all branches + +def handle_command(command: str, args: List[str]) -> bool: + """ + Handle rollover commands with seedgo-compliant introspection. + + Routing: + rollover (no args) -> print_introspection() + rollover --help/-h/help -> print_help() + rollover run -> execute rollover + rollover status -> show rollover status + rollover check -> dry-run check + rollover sync-lines -> sync line counts + + Backward-compatible top-level commands (routed from entry point): + status, check, sync-lines -> forwarded directly Args: command: Command name @@ -62,15 +76,50 @@ def handle_command(command: str, args: List[str]) -> bool: # noqa: ARG001 Returns: True if command handled, False otherwise """ + # Top-level help (backward compat — entry point may send these) if command in ('--help', '-h', 'help'): print_help() return True if command == 'rollover': - run_rollover() + # No args → introspection (seedgo standard) + if not args: + print_introspection() + return True + + # --help / -h / help → full help + if args[0] in ('--help', '-h', 'help'): + print_help() + return True + + # Subcommand routing + sub = args[0] + + if sub == 'run': + run_rollover() + return True + + if sub == 'status': + show_status() + return True + + if sub == 'check': + check_triggers() + return True + + if sub == 'sync-lines': + sync_line_counts() + return True + + # Unknown subcommand + error( + f"Unknown subcommand: '{sub}'", + suggestion="Available: " + ", ".join(_SUBCOMMANDS.keys()), + ) return True - elif command == 'status': + # Backward-compatible top-level commands (entry point still routes these) + if command == 'status': show_status() return True @@ -318,19 +367,66 @@ def check_triggers() -> None: # INTROSPECTION # ============================================================================= -def print_introspection(): - """Display module introspection info.""" +def _discover_handlers() -> dict[str, list[str]]: + """Auto-discover handler directories and their Python files. + + Scans the handlers/ directory relative to this module. + + Returns: + Dict mapping handler directory name to list of .py filenames + (excluding __init__.py and __pycache__). + """ + handlers_dir = Path(__file__).resolve().parent.parent / "handlers" + result: dict[str, list[str]] = {} + if not handlers_dir.exists(): + return result + for d in sorted(handlers_dir.iterdir()): + if not d.is_dir() or d.name.startswith("__"): + continue + py_files = sorted( + f.name for f in d.iterdir() + if f.is_file() and f.suffix == ".py" and f.name != "__init__.py" + ) + if py_files: + result[d.name] = py_files + return result + + +def print_introspection() -> None: + """Display module introspection info (seedgo standard). + + Called when 'rollover' is invoked with no arguments. + Shows module identity, connected handlers, available subcommands, + and next-step hints. + """ console.print() - console.print("rollover Module") + console.print("[bold cyan]rollover Module[/bold cyan]") console.print("Orchestrates memory rollover workflow: trigger detection, extraction, embedding, and vector storage") console.print() - console.print("Connected Handlers:") - console.print(" handlers/monitor/") - console.print(" - detector.py (check_all_branches — detect branches exceeding rollover threshold)") - console.print(" - detector.py (get_rollover_stats — retrieve rollover statistics for all branches)") - console.print(" handlers/rollover/") - console.print(" - orchestrator.py (execute_rollover — run full rollover pipeline for triggered branches)") - console.print(" - orchestrator.py (sync_line_counts — update line count metadata for all memory files)") + + # Connected handlers (auto-discovered) + handlers = _discover_handlers() + console.print("[yellow]Connected Handlers:[/yellow]") + if handlers: + for dir_name, files in handlers.items(): + file_list = ", ".join(files) + console.print(f" [cyan]handlers/{dir_name}/[/cyan] [dim]{file_list}[/dim]") + else: + console.print(" [dim]No handlers found[/dim]") + console.print() + + # Available subcommands + console.print("[yellow]Subcommands:[/yellow]") + for sub, desc in _SUBCOMMANDS.items(): + console.print(f" [green]{sub:<14}[/green] {desc}") + console.print() + + # Next-step hints + console.print("[yellow]Next:[/yellow]") + console.print(" [green]drone @memory rollover run[/green] [dim]# Execute rollover[/dim]") + console.print(" [green]drone @memory rollover status[/green] [dim]# View rollover stats[/dim]") + console.print(" [green]drone @memory rollover check[/green] [dim]# Dry-run check[/dim]") + console.print(" [green]drone @memory rollover --help[/green] [dim]# Full usage guide[/dim]") console.print() @@ -341,9 +437,14 @@ def print_introspection(): if __name__ == "__main__": import sys - # Handle --help before argparse (module standard) - if len(sys.argv) < 2 or sys.argv[1] in ('--help', '-h', 'help'): - handle_command('help', []) + # No args → introspection (seedgo standard) + if len(sys.argv) < 2: + handle_command('rollover', []) + sys.exit(0) + + # --help → full help + if sys.argv[1] in ('--help', '-h', 'help'): + handle_command('rollover', ['--help']) sys.exit(0) # Execute command via handle_command diff --git a/src/aipass/memory/apps/modules/search.py b/src/aipass/memory/apps/modules/search.py index 75e70ad0..2897ad6d 100755 --- a/src/aipass/memory/apps/modules/search.py +++ b/src/aipass/memory/apps/modules/search.py @@ -1,9 +1,9 @@ # =================== AIPass ==================== # Name: search.py # Description: Search Orchestration Module -# Version: 0.4.0 +# Version: 0.5.0 # Created: 2025-11-27 -# Modified: 2026-03-08 +# Modified: 2026-03-15 # ============================================= """ @@ -20,6 +20,7 @@ Purpose: """ import sys +from pathlib import Path from typing import List from rich.panel import Panel @@ -44,11 +45,15 @@ from aipass.memory.apps.handlers.search.query_executor import ( def handle_command(command: str, args: List[str]) -> bool: """ - Handle search commands + Handle search commands with seedgo-compliant introspection. - Commands supported: - - search : Execute semantic search across all branches - - help: Show search help + Routing: + search (no args) -> print_introspection() + search --help/-h/help -> print_help() + search [options] -> execute query + + Backward-compatible top-level commands (routed from entry point): + --help, -h, help -> print_help() Args: command: Command name @@ -57,13 +62,20 @@ def handle_command(command: str, args: List[str]) -> bool: Returns: True if command handled, False otherwise """ + # Top-level help (backward compat — entry point may send these) if command in ('--help', '-h', 'help'): print_help() return True if command == 'search': + # No args → introspection (seedgo standard) if not args: - error("Search query required", suggestion="Usage: search [--branch BRANCH] [--type TYPE] [--n N]") + print_introspection() + return True + + # --help / -h / help → full help + if args[0] in ('--help', '-h', 'help'): + print_help() return True # Parse arguments @@ -251,15 +263,58 @@ def show_search_results( # INTROSPECTION # ============================================================================= -def print_introspection(): - """Display module introspection info.""" +def _discover_handlers() -> dict[str, list[str]]: + """Auto-discover handler directories and their Python files. + + Scans the handlers/ directory relative to this module. + + Returns: + Dict mapping handler directory name to list of .py filenames + (excluding __init__.py and __pycache__). + """ + handlers_dir = Path(__file__).resolve().parent.parent / "handlers" + result: dict[str, list[str]] = {} + if not handlers_dir.exists(): + return result + for d in sorted(handlers_dir.iterdir()): + if not d.is_dir() or d.name.startswith("__"): + continue + py_files = sorted( + f.name for f in d.iterdir() + if f.is_file() and f.suffix == ".py" and f.name != "__init__.py" + ) + if py_files: + result[d.name] = py_files + return result + + +def print_introspection() -> None: + """Display module introspection info (seedgo standard). + + Called when 'search' is invoked with no arguments. + Shows module identity, connected handlers, and next-step hints. + """ console.print() - console.print("search Module") + console.print("[bold cyan]search Module[/bold cyan]") console.print("Orchestrates semantic search across memory collections via vector embeddings and ChromaDB") console.print() - console.print("Connected Handlers:") - console.print(" handlers/search/") - console.print(" - query_executor.py (execute_search — encode query, search collections, filter results by similarity)") + + # Connected handlers (auto-discovered) + handlers = _discover_handlers() + console.print("[yellow]Connected Handlers:[/yellow]") + if handlers: + for dir_name, files in handlers.items(): + file_list = ", ".join(files) + console.print(f" [cyan]handlers/{dir_name}/[/cyan] [dim]{file_list}[/dim]") + else: + console.print(" [dim]No handlers found[/dim]") + console.print() + + # Next-step hints + console.print("[yellow]Next:[/yellow]") + console.print(' [green]drone @memory search "your query"[/green] [dim]# Semantic search[/dim]') + console.print(' [green]drone @memory search "query" --branch SEED[/green] [dim]# Filter by branch[/dim]') + console.print(" [green]drone @memory search --help[/green] [dim]# Full usage guide[/dim]") console.print() @@ -268,9 +323,14 @@ def print_introspection(): # ============================================================================= if __name__ == "__main__": - # Handle --help before argparse (module standard) - if len(sys.argv) < 2 or sys.argv[1] in ('--help', '-h', 'help'): - handle_command('help', []) + # No args → introspection (seedgo standard) + if len(sys.argv) < 2: + handle_command('search', []) + sys.exit(0) + + # --help → full help + if sys.argv[1] in ('--help', '-h', 'help'): + handle_command('search', ['--help']) sys.exit(0) # Execute command via handle_command