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:
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user