mirror of
https://github.com/the-jordan-lab/docs.git
synced 2025-05-09 21:32:38 +00:00
155 lines
5.8 KiB
Python
155 lines
5.8 KiB
Python
![]() |
#!/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()
|