feat: Make ast-stats command work without file argument - show AST subsystem statistics

Enhanced ast-stats command to follow the established *-stats convention where subsystem
commands show system-level statistics when called without specific targets.

## Changes Made:

### 1. Made file_path Argument Optional
- Changed from required to optional: `@click.argument('file_path', required=False)`
- Updated help text to show `[FILE_PATH]` indicating optional parameter
- Enhanced docstring with clear examples for both usage patterns

### 2. Implemented AST Subsystem Statistics
- New function `_show_ast_subsystem_stats()` for system-level statistics
- Comprehensive statistics collection including:
  * **AST Cache**: Directory path, cached files count, cache size
  * **Processing Metrics**: Total files processed, recent activity (7 days)
  * **System Information**: Service availability, working directory, Python version

### 3. Dual Functionality Support
```bash
markitect ast-stats              # Shows AST subsystem statistics
markitect ast-stats document.md  # Shows file-specific analysis (preserved)
```

### 4. Consistent Output Formats
- Supports all formats: table, json, yaml, simple
- Table format: Organized with emoji icons and status indicators
- JSON/YAML: Structured data for programmatic use
- Simple: Key-value pairs for scripting

### 5. Robust Error Handling
- Graceful degradation when cache/database unavailable
- Clear status indicators ( Available,  Unavailable, ⚠️ Warning)
- Detailed error messages in verbose mode

## Implementation Details:

The command now detects when no file is provided and automatically switches to
subsystem mode, maintaining full backward compatibility with existing file
analysis functionality.

Benefits:
- **Consistent CLI Experience**: Matches cache-stats, db-stats, config-stats patterns
- **System Monitoring**: Easy way to check AST subsystem health
- **Backward Compatible**: Existing scripts continue to work unchanged
- **Professional Interface**: Clear separation between system and file-level stats

All functionality tested and working correctly with comprehensive error handling.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-30 22:25:30 +02:00
parent cbf82b74cb
commit fd66d67849

View File

@@ -1081,25 +1081,180 @@ def ast_query(config, file_path, jsonpath, format):
sys.exit(1) sys.exit(1)
def _show_ast_subsystem_stats(config, format):
"""Display AST subsystem statistics including cache and processing metrics."""
try:
# Import dependencies
from .ast_cache import ASTCache
from .cache_service import CacheDirectoryService
# Collect AST subsystem statistics
stats = {}
# AST Cache information
try:
cache_service = CacheDirectoryService()
cache_stats = cache_service.get_cache_stats()
stats['ast_cache'] = {
'directory': cache_stats.get('cache_directory', 'Unknown'),
'total_files': cache_stats.get('total_files', 0),
'cache_size_bytes': cache_stats.get('cache_size_bytes', 0),
'cache_size_human': cache_stats.get('cache_size_human', '0 B'),
'available': True
}
except Exception as e:
stats['ast_cache'] = {
'available': False,
'error': str(e)
}
# Database statistics (files processed)
try:
db_manager = config.get('db_manager')
if db_manager:
# Get count of files in database (processed files)
conn = db_manager.get_connection()
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM markdown_files")
total_files = cursor.fetchone()[0]
# Get recent processing info
cursor.execute("""
SELECT COUNT(*) FROM markdown_files
WHERE created_at >= datetime('now', '-7 days')
""")
recent_files = cursor.fetchone()[0]
stats['processing'] = {
'total_files_processed': total_files,
'files_processed_last_7_days': recent_files,
'database_available': True
}
else:
stats['processing'] = {
'database_available': False,
'message': 'Database not initialized'
}
except Exception as e:
stats['processing'] = {
'database_available': False,
'error': str(e)
}
# System information
stats['system'] = {
'ast_service_available': True, # If we got here, it's available
'working_directory': os.getcwd(),
'python_version': sys.version.split()[0]
}
# Format output
if format == 'json':
click.echo(json.dumps(stats, indent=2))
elif format == 'yaml':
click.echo(yaml.dump(stats, default_flow_style=False))
elif format == 'simple':
# Simple key-value output
if stats['ast_cache']['available']:
cache = stats['ast_cache']
click.echo(f"ast_cache_directory: {cache['directory']}")
click.echo(f"ast_cache_files: {cache['total_files']}")
click.echo(f"ast_cache_size: {cache['cache_size_human']}")
else:
click.echo(f"ast_cache_available: False")
if stats['processing']['database_available']:
proc = stats['processing']
click.echo(f"total_files_processed: {proc['total_files_processed']}")
click.echo(f"recent_files_processed: {proc['files_processed_last_7_days']}")
else:
click.echo("database_available: False")
sys_info = stats['system']
click.echo(f"working_directory: {sys_info['working_directory']}")
click.echo(f"python_version: {sys_info['python_version']}")
else: # table format (default)
click.echo("📊 AST Subsystem Statistics")
click.echo("=" * 50)
# AST Cache section
click.echo("\n🗃️ AST Cache:")
if stats['ast_cache']['available']:
cache = stats['ast_cache']
click.echo(f" Directory: {cache['directory']}")
click.echo(f" Cached Files: {cache['total_files']}")
click.echo(f" Cache Size: {cache['cache_size_human']}")
if cache['total_files'] == 0:
click.echo(" Status: ⚠️ No files cached yet")
else:
click.echo(f" Status: ✅ Active")
else:
click.echo(" Status: ❌ Unavailable")
if 'error' in stats['ast_cache']:
click.echo(f" Error: {stats['ast_cache']['error']}")
# Processing section
click.echo("\n⚙️ Processing Metrics:")
if stats['processing']['database_available']:
proc = stats['processing']
click.echo(f" Total Files Processed: {proc['total_files_processed']}")
click.echo(f" Files Processed (Last 7 Days): {proc['files_processed_last_7_days']}")
if proc['total_files_processed'] == 0:
click.echo(" Status: ⚠️ No files processed yet")
else:
click.echo(" Status: ✅ Active")
else:
click.echo(" Status: ❌ Database unavailable")
if 'error' in stats['processing']:
click.echo(f" Error: {stats['processing']['error']}")
elif 'message' in stats['processing']:
click.echo(f" Note: {stats['processing']['message']}")
# System section
click.echo("\n🖥️ System Information:")
sys_info = stats['system']
click.echo(f" AST Service: ✅ Available")
click.echo(f" Working Directory: {sys_info['working_directory']}")
click.echo(f" Python Version: {sys_info['python_version']}")
except Exception as e:
click.echo(f"Error gathering AST subsystem statistics: {e}", err=True)
if config.get('verbose'):
import traceback
click.echo(traceback.format_exc(), err=True)
@cli.command('ast-stats') @cli.command('ast-stats')
@click.argument('file_path', type=click.Path(exists=False)) @click.argument('file_path', type=click.Path(exists=False), required=False)
@click.option('--format', '-f', type=click.Choice(['table', 'json', 'yaml', 'simple']), default='table', help='Output format') @click.option('--format', '-f', type=click.Choice(['table', 'json', 'yaml', 'simple']), default='table', help='Output format')
@pass_config @pass_config
def ast_stats(config, file_path, format): def ast_stats(config, file_path, format):
""" """
Show AST statistics (headings, links, etc.). Show AST statistics for files or AST subsystem information.
Analyze markdown file structure and provide comprehensive statistics When called with a file: Analyze markdown file structure and provide
about document elements, organization, and content patterns. comprehensive statistics about document elements, organization, and content patterns.
FILE_PATH: Path to the markdown file to analyze When called without a file: Show AST subsystem statistics including cache
information, processing metrics, and system status.
FILE_PATH: Optional path to the markdown file to analyze
Examples: Examples:
markitect ast-stats document.md markitect ast-stats # Show AST subsystem statistics
markitect ast-stats document.md # Analyze specific file
markitect ast-stats document.md --format json markitect ast-stats document.md --format json
markitect ast-stats document.md --format yaml
""" """
try: try:
# If no file provided, show AST subsystem statistics
if not file_path:
if config.get('verbose'):
click.echo("Displaying AST subsystem statistics", err=True)
_show_ast_subsystem_stats(config, format)
return
# File-specific analysis (existing behavior)
if config.get('verbose'): if config.get('verbose'):
click.echo(f"Calculating statistics for: {file_path}", err=True) click.echo(f"Calculating statistics for: {file_path}", err=True)