docs/Agent/tools/update_robot_readme.py

155 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Robot README Updater
This script automatically updates ROBOT_README.md based on the repository structure.
It scans for top-level markdown files and directories, generating a structured table
of contents for AI assistants to understand the repository organization.
Usage:
python update_robot_readme.py
This can be run manually or as a pre-commit hook to ensure the robot table of
contents stays in sync with the repository.
"""
import os
import re
from collections import defaultdict
from pathlib import Path
# Configuration
ROBOT_README = "ROBOT_README.md"
REPO_ROOT = "." # Current directory
EXCLUDE_DIRS = [".git", ".github", ".vscode", "__pycache__", "node_modules"]
EXCLUDE_FILES = [ROBOT_README] # Don't include self in the listing
# Descriptions for known files and directories
FILE_DESCRIPTIONS = {
"README.md": "Main repository README with quick-start instructions and overview.",
"ENVIRONMENT_SETUP.md": "Guide for setting up the development environment, including GitHub CLI and OpenAI API key configuration.",
"LAB_AGENT_GUIDE.md": "Detailed guide on how to use the Lab Agent, including examples and troubleshooting.",
"TASKS.md": "Tracks ongoing lab and development tasks, automatically updated by the Lab Agent.",
"ISSUES_LOG.md": "Logs all GitHub issues created, automatically updated by the Lab Agent.",
"morning_push_2025-05-06.md": "Checklist for May 6, 2025 morning push tasks.",
"morning_push_2025-05-07.md": "Checklist for May 7, 2025 morning push tasks.",
}
DIR_DESCRIPTIONS = {
"Protocols": "Contains standard operating procedures and experimental protocols.",
"Projects": "Groups related experiments under broad project titles.",
"Experiments": "Records of individual experiments or lab sessions.",
"Data": "Storage for data outputs or references to data.",
"Templates": "Contains starter templates for various YAML structures.",
"Agent": "Contains the code for the AI agent integration, including the task-runner and hooks.",
}
def scan_repository():
"""Scan the repository for top-level markdown files and directories."""
md_files = []
directories = []
for item in os.listdir(REPO_ROOT):
path = Path(os.path.join(REPO_ROOT, item))
# Skip excluded items
if item in EXCLUDE_DIRS or item in EXCLUDE_FILES:
continue
# Skip hidden files and directories
if item.startswith('.'):
continue
if path.is_file() and item.endswith('.md'):
md_files.append(item)
elif path.is_dir() and not item.startswith('.'):
directories.append(item)
return sorted(md_files), sorted(directories)
def extract_existing_descriptions():
"""Extract existing descriptions from ROBOT_README.md if it exists."""
descriptions = defaultdict(str)
if not os.path.exists(ROBOT_README):
return descriptions
with open(ROBOT_README, 'r') as f:
content = f.read()
# Extract existing descriptions using regex
file_matches = re.findall(r'\*\*([^*]+\.md)\*\*:\s*([^\n]+)', content)
dir_matches = re.findall(r'\*\*([^*]+)/\*\*:\s*([^\n]+)', content)
for name, desc in file_matches + dir_matches:
descriptions[name] = desc.strip()
return descriptions
def get_description(item, is_dir, existing_descriptions):
"""Get description for an item, using existing description if available."""
if item in (FILE_DESCRIPTIONS if not is_dir else DIR_DESCRIPTIONS):
return FILE_DESCRIPTIONS[item] if not is_dir else DIR_DESCRIPTIONS[item]
elif item in existing_descriptions:
return existing_descriptions[item]
else:
return "No description available." if not is_dir else "Directory containing repository files."
def generate_robot_readme(md_files, directories, existing_descriptions):
"""Generate the content for ROBOT_README.md."""
content = [
"# Robot Table of Contents",
"",
"This file serves as a robot table of contents for the repository. It lists the structure of the repository and points to relevant .md files for context.",
"",
"## Repository Structure",
""
]
# Add markdown files
if md_files:
for file in md_files:
description = get_description(file, False, existing_descriptions)
content.append(f"- **{file}**: {description}")
content.append("")
# Add directories section
if directories:
content.append("## Additional Directories")
content.append("")
for directory in directories:
description = get_description(directory, True, existing_descriptions)
content.append(f"- **{directory}/**: {description}")
content.append("")
# Add footer
content.append("---")
content.append("")
content.append("_This file will be updated whenever the repository structure changes to ensure the robot has the latest context._")
return "\n".join(content)
def update_robot_readme():
"""Update ROBOT_README.md if the content has changed."""
existing_descriptions = extract_existing_descriptions()
md_files, directories = scan_repository()
new_content = generate_robot_readme(md_files, directories, existing_descriptions)
# Check if the file exists and if content has changed
if os.path.exists(ROBOT_README):
with open(ROBOT_README, 'r') as f:
current_content = f.read()
if current_content.strip() == new_content.strip():
print(f"No changes needed for {ROBOT_README}")
return False
# Write the updated content
with open(ROBOT_README, 'w') as f:
f.write(new_content)
print(f"Updated {ROBOT_README} with latest repository structure")
return True
if __name__ == "__main__":
update_robot_readme()