Skip to main content

scripts-generate-activation-status

#!/usr/bin/env python3 """​

title: "Get script directory for path resolution (works from any cwd)" component_type: script version: "1.0.0" audience: contributor status: stable summary: "Generate Component Activation Status" keywords: ['activation', 'generate', 'status'] tokens: ~500 created: 2025-12-22 updated: 2025-12-22 script_name: "generate-activation-status.py" language: python executable: true usage: "python3 scripts/generate-activation-status.py [options]" python_version: "3.10+" dependencies: [] modifies_files: false network_access: false requires_auth: false​

Generate Component Activation Status

Creates component-activation-status.json following Anthropic's feature_list.json pattern. Tracks which components are activated across sessions for multi-session continuity.

Part of Phase 5: Multi-Session Integration Created: 2025-11-29 """

import json import argparse from pathlib import Path from datetime import datetime, timezone from typing import Dict, List, Any

Get script directory for path resolution (works from any cwd)

SCRIPT_DIR = Path(file).resolve().parent CORE_ROOT = SCRIPT_DIR.parent

Critical components that should always be activated

CRITICAL_COMPONENTS = { 'agent': [ 'codi-documentation-writer', 'orchestrator', 'codebase-locator', 'codebase-analyzer', 'documentation-librarian' ], 'script': [ 'component_activator.py', 'registry_loader.py', 'framework_bridge.py', 'agent_dispatcher.py' ] }

def load_framework_registry(registry_path: Path) -> Dict[str, Any]: """Load framework-registry.json""" if not registry_path.exists(): raise FileNotFoundError(f"Registry not found: {registry_path}")

with open(registry_path, 'r') as f:
return json.load(f)

def is_critical_component(component_type: str, component_name: str) -> bool: """Check if component is critical and should be auto-activated""" return component_name in CRITICAL_COMPONENTS.get(component_type, [])

def generate_activation_entry(component: Dict[str, Any]) -> Dict[str, Any]: """ Generate activation entry for a single component.

Follows Anthropic's feature_list.json pattern:
- JSON format (prevents LLM modification)
- Boolean activated field (like 'passes')
- Timestamps for audit trail
- Reason for documentation
"""
component_type = component.get('type', 'unknown')
component_name = component.get('name', 'unknown')

# Determine default activation state
activated = is_critical_component(component_type, component_name)

entry = {
'type': component_type,
'name': component_name,
'path': component.get('path', ''),
'activated': activated,
'version': component.get('version', '1.0.0'),
'status': component.get('status', 'operational')
}

# Add timestamp and reason based on activation
now = datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
if activated:
entry['activated_at'] = now
entry['reason'] = 'Critical component - auto-activated'
else:
entry['reason'] = 'Available - activate when needed'

return entry

def generate_activation_status(registry: Dict[str, Any]) -> Dict[str, Any]: """ Generate complete component-activation-status.json

Structure follows Anthropic pattern:
- version, last_updated (metadata)
- activation_summary (statistics)
- components (array of activation entries)
"""
components_list = []

# Process all component types
for component_type, components in registry.get('components', {}).items():
for component in components:
entry = generate_activation_entry(component)
components_list.append(entry)

# Sort components by type, then by name
components_list.sort(key=lambda x: (x['type'], x['name']))

# Calculate activation summary
total = len(components_list)
activated = sum(1 for c in components_list if c['activated'])
deactivated = total - activated

# Build final structure
activation_status = {
'version': '1.0.0',
'last_updated': datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z'),
'activation_summary': {
'total_components': total,
'activated': activated,
'deactivated': deactivated
},
'components': components_list
}

return activation_status

def atomic_write(file_path: Path, data: Dict[str, Any]) -> None: """ Atomic write to prevent corruption during writes.

Writes to temp file first, then renames.
Follows Anthropic's safe file handling pattern.
"""
temp_path = file_path.with_suffix('.tmp')

try:
# Write to temp file
with open(temp_path, 'w') as f:
json.dump(data, f, indent=2, sort_keys=False)
f.write('\n') # Add trailing newline

# Atomic rename
temp_path.replace(file_path)
print(f"āœ… Written: {file_path}")
except Exception as e:
# Clean up temp file on error
if temp_path.exists():
temp_path.unlink()
raise e

def main(): """Main entry point""" parser = argparse.ArgumentParser( description='Generate component activation status file' ) parser.add_argument( '--registry', type=Path, default=CORE_ROOT / 'config' / 'framework-registry.json', help='Path to framework-registry.json' ) parser.add_argument( '--output', type=Path, default=CORE_ROOT / '.claude' / 'component-activation-status.json', help='Output path for activation status' ) parser.add_argument( '--verbose', action='store_true', help='Verbose output' ) parser.add_argument( '--dry-run', action='store_true', help='Print JSON without writing file' )

args = parser.parse_args()

# Load framework registry
if args.verbose:
print(f"šŸ“– Loading registry: {args.registry}")

registry = load_framework_registry(args.registry)

if args.verbose:
print(f"āœ“ Loaded {registry.get('total_components', 0)} components")

# Generate activation status
activation_status = generate_activation_status(registry)

summary = activation_status['activation_summary']
print(f"\nšŸ“Š Activation Status Generated:")
print(f" Total: {summary['total_components']}")
print(f" Activated: {summary['activated']} (critical components)")
print(f" Deactivated: {summary['deactivated']} (available)")

# Write or print
if args.dry_run:
print(f"\nšŸ” DRY RUN - Would write to: {args.output}")
print(json.dumps(activation_status, indent=2))
else:
# Ensure output directory exists
args.output.parent.mkdir(parents=True, exist_ok=True)

# Atomic write
atomic_write(args.output, activation_status)

print(f"\nāœ… Activation status saved: {args.output}")
print(f" Components can now be activated/deactivated via:")
print(f" - scripts/update-component-activation.py")
print(f" - coditect activate/deactivate commands")

if name == 'main': main()