scripts-organize-production
#!/usr/bin/env python3 """ā
title: "=============================================================================" component_type: script version: "1.0.0" audience: contributor status: stable summary: "organize_production.py - Production Folder Organization Script" keywords: ['api', 'backend', 'deployment', 'frontend', 'git'] tokens: ~500 created: 2025-12-22 updated: 2025-12-22 script_name: "organize_production.py" language: python executable: true usage: "python3 scripts/organize_production.py [options]" python_version: "3.10+" dependencies: [] modifies_files: false network_access: false requires_auth: falseā
organize_production.py - Production Folder Organization Script
Standalone CLI tool for organizing projects to CODITECT production standards. Integrates with production-folder-structure skill and project-organizer agent.
Usage: python3 organize_production.py [options]
Options:
--validate Validation only (no changes)
--dry-run Show plan without executing
--auto-fix Automatically fix issues (requires approval)
--score Show production readiness score only
--type
Examples: # Validate current structure python3 organize_production.py --validate
# Show production readiness score
python3 organize_production.py --score
# Generate organization plan (dry run)
python3 organize_production.py --dry-run
# Execute organization with approval
python3 organize_production.py
# Auto-fix with confirmation
python3 organize_production.py --auto-fix
Version: 1.0.0 Last Updated: 2025-12-04 Author: CODITECT Core Team """
import argparse import json import os import subprocess import sys from pathlib import Path from typing import Dict, List, Optional, Tuple
=============================================================================
PROJECT TYPE DETECTION
=============================================================================
def detect_project_type(path: str) -> str: """ Detect project type based on file/directory indicators.
Priority:
1. Monorepo (workspace configs)
2. Frontend (components/, public/)
3. Backend (routes/, models/, migrations/)
4. Universal (fallback)
Returns:
"monorepo" | "frontend" | "backend" | "universal"
"""
path_obj = Path(path)
# Check for monorepo indicators
monorepo_files = [
"pnpm-workspace.yaml",
"nx.json",
"turbo.json",
"lerna.json"
]
for file in monorepo_files:
if (path_obj / file).exists():
return "monorepo"
# Check for monorepo directory structure
if (path_obj / "apps").exists() and (
(path_obj / "libs").exists() or (path_obj / "packages").exists()
):
return "monorepo"
# Check for frontend indicators
frontend_indicators = [
path_obj / "src" / "components",
path_obj / "app",
path_obj / "public",
path_obj / "index.html",
path_obj / "vite.config.ts",
path_obj / "next.config.js"
]
if any(indicator.exists() for indicator in frontend_indicators):
return "frontend"
# Check for backend indicators
backend_indicators = [
path_obj / "src" / "routes",
path_obj / "src" / "api",
path_obj / "src" / "handlers",
path_obj / "src" / "models",
path_obj / "migrations",
path_obj / "requirements.txt",
path_obj / "Cargo.toml"
]
if any(indicator.exists() for indicator in backend_indicators):
return "backend"
# Default to universal
return "universal"
=============================================================================
VALIDATION
=============================================================================
def validate_structure(path: str, project_type: str) -> Dict: """ Validate project structure against production standards.
Returns:
{
"score": int (0-100),
"universal_score": int,
"project_specific_score": int,
"violations": List[str],
"missing_files": List[str],
"status": "ready" | "needs_improvement" | "not_ready"
}
"""
path_obj = Path(path)
violations = []
missing_files = []
# Check required universal files
required_files = [
"README.md",
"CLAUDE.md",
"CONTRIBUTING.md",
"CHANGELOG.md",
"LICENSE",
"SECURITY.md",
".gitignore"
]
for file in required_files:
if not (path_obj / file).exists():
missing_files.append(file)
# Check docs/ hierarchy
required_docs_dirs = [
"docs/architecture",
"docs/architecture/adrs",
"docs/deployment",
"docs/project-management",
"docs/project-management/checkpoints",
"docs/testing",
"docs/user-guides"
]
for dir_path in required_docs_dirs:
if not (path_obj / dir_path).exists():
missing_files.append(dir_path + "/")
# Check scripts/
if not (path_obj / "scripts").exists():
missing_files.append("scripts/")
# Check root cleanliness
root_items = list(path_obj.iterdir())
if len(root_items) > 25:
violations.append(f"Root directory has {len(root_items)} items (guideline: ā¤25)")
# Calculate scores
universal_max = 60
project_specific_max = 40
# Universal scoring
doc_files_score = max(0, 15 - (len([f for f in missing_files if not f.endswith("/")]) * 2.5))
doc_hierarchy_score = max(0, 15 - (len([f for f in missing_files if f.endswith("/")]) * 2))
scripts_score = 15 if (path_obj / "scripts").exists() else 5
config_score = 15 if (path_obj / ".gitignore").exists() else 10
universal_score = int(doc_files_score + doc_hierarchy_score + scripts_score + config_score)
# Project-specific scoring (simplified)
project_specific_score = 30 # Placeholder
total_score = min(100, universal_score + project_specific_score)
# Determine status
if total_score >= 90:
status = "ready"
elif total_score >= 70:
status = "needs_improvement"
else:
status = "not_ready"
return {
"score": total_score,
"universal_score": universal_score,
"project_specific_score": project_specific_score,
"violations": violations,
"missing_files": missing_files,
"status": status
}
=============================================================================
MAIN CLI
=============================================================================
def main(): parser = argparse.ArgumentParser( description="Organize project to CODITECT production standards", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=doc )
parser.add_argument("--validate", action="store_true",
help="Validation only (no changes)")
parser.add_argument("--dry-run", action="store_true",
help="Show plan without executing")
parser.add_argument("--auto-fix", action="store_true",
help="Automatically fix issues (requires approval)")
parser.add_argument("--score", action="store_true",
help="Show production readiness score only")
parser.add_argument("--type", choices=["frontend", "backend", "monorepo"],
help="Force project type")
parser.add_argument("--path", default=".",
help="Project path (default: current directory)")
args = parser.parse_args()
# Resolve path
project_path = Path(args.path).resolve()
if not project_path.exists():
print(f"Error: Path does not exist: {project_path}", file=sys.stderr)
sys.exit(1)
# Detect or use forced project type
if args.type:
project_type = args.type
print(f"š Project Type: {project_type.capitalize()} (forced)")
else:
project_type = detect_project_type(str(project_path))
print(f"š Project Type Detected: {project_type.capitalize()}")
# Validate structure
validation_result = validate_structure(str(project_path), project_type)
# Show score
print(f"\nš Production Readiness Score: {validation_result['score']}/100")
print(f" Universal: {validation_result['universal_score']}/60")
print(f" {project_type.capitalize()}-Specific: {validation_result['project_specific_score']}/40")
status_emoji = {
"ready": "ā
",
"needs_improvement": "š”",
"not_ready": "ā"
}
print(f" Status: {status_emoji[validation_result['status']]} {validation_result['status'].replace('_', ' ').title()}")
# Show violations and missing files
if validation_result['violations']:
print("\nā ļø Violations:")
for violation in validation_result['violations']:
print(f" - {violation}")
if validation_result['missing_files']:
print("\nš Missing Files/Directories:")
for missing in validation_result['missing_files'][:10]: # Show first 10
print(f" - {missing}")
if len(validation_result['missing_files']) > 10:
print(f" ... and {len(validation_result['missing_files']) - 10} more")
# Exit if score-only mode
if args.score:
sys.exit(0)
# Exit if validate-only mode
if args.validate:
print("\nā Validation complete (no changes made)")
sys.exit(0)
# Show recommendation
print("\nš” Recommendation:")
print(" For complete organization, use Claude Code:")
print(" /organize-production")
print("\n Or use the project-organizer agent:")
print(" Task(subagent_type='project-organizer', ...)")
sys.exit(0)
if name == "main": main()