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)
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')
@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')
@pass_config
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
about document elements, organization, and content patterns.
When called with a file: Analyze markdown file structure and provide
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:
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 yaml
"""
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'):
click.echo(f"Calculating statistics for: {file_path}", err=True)