feat(memory): CLI introspection overhaul — seedgo-compliant discovery

Wire print_introspection() into both modules with no-args gate per seedgo
introspection standard. Rollover bare command now shows handlers + subcommands
instead of executing. Search bare command shows introspection instead of error.
Fix bug where `search --help` ran a search for "--help". Remove 5 ghost
commands from help text. Restructure rollover as subcommands (run/status/check/
sync-lines).

DPLAN-0045, FPLAN-0047, FPLAN-0049

Co-Authored-By: @memory <memory@aipass>
This commit is contained in:
AIOSAI
2026-03-15 20:22:11 -07:00
co-authored by @memory
parent 07f2a6cf8f
commit 410b2e44e2
3 changed files with 212 additions and 50 deletions
+10 -9
View File
@@ -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 <query>", "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()
+126 -25
View File
@@ -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
+76 -16
View File
@@ -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 <query>: Execute semantic search across all branches
- help: Show search help
Routing:
search (no args) -> print_introspection()
search --help/-h/help -> print_help()
search <query> [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 <query> [--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