Consolidate the repository into clearer apps, tools, and layered docs areas so contributors can navigate and maintain it more reliably. Align validation, metadata sync, and CI around the same canonical workflow to reduce drift across local checks and GitHub Actions.
54 lines
2.0 KiB
Python
54 lines
2.0 KiB
Python
import os
|
|
import re
|
|
from _project_paths import find_repo_root
|
|
|
|
def fix_dangling_links(skills_dir):
|
|
print(f"Scanning for dangling links in {skills_dir}...")
|
|
pattern = re.compile(r'\[([^\]]*)\]\(([^)]+)\)')
|
|
fixed_count = 0
|
|
|
|
for root, dirs, files in os.walk(skills_dir):
|
|
# Skip hidden directories
|
|
dirs[:] = [d for d in dirs if not d.startswith('.')]
|
|
for file in files:
|
|
if not file.endswith('.md'): continue
|
|
|
|
file_path = os.path.join(root, file)
|
|
try:
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
except Exception:
|
|
continue
|
|
|
|
def replacer(match):
|
|
nonlocal fixed_count
|
|
text = match.group(1)
|
|
href = match.group(2)
|
|
href_clean = href.split('#')[0].strip()
|
|
|
|
# Ignore empty links, web URLs, emails, etc.
|
|
if not href_clean or href_clean.startswith(('http://', 'https://', 'mailto:', '<', '>')):
|
|
return match.group(0)
|
|
if os.path.isabs(href_clean):
|
|
return match.group(0)
|
|
|
|
target_path = os.path.normpath(os.path.join(root, href_clean))
|
|
if not os.path.exists(target_path):
|
|
# Dangling link detected. Replace markdown link with just its text.
|
|
print(f"Fixing dangling link in {os.path.relpath(file_path, skills_dir)}: {href}")
|
|
fixed_count += 1
|
|
return text
|
|
return match.group(0)
|
|
|
|
new_content = pattern.sub(replacer, content)
|
|
|
|
if new_content != content:
|
|
with open(file_path, 'w', encoding='utf-8') as f:
|
|
f.write(new_content)
|
|
|
|
print(f"Total dangling links fixed: {fixed_count}")
|
|
|
|
if __name__ == '__main__':
|
|
base_dir = str(find_repo_root(__file__))
|
|
fix_dangling_links(os.path.join(base_dir, 'skills'))
|