Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)
Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
66 lines
1.8 KiB
Python
66 lines
1.8 KiB
Python
"""Filename generation with collision avoidance.
|
|
|
|
Pattern: YYYY-MM-DD-slugified-title.md
|
|
Slug: lowercase alphanumeric + hyphens only.
|
|
Appends numeric suffix (-2, -3, ...) if file already exists.
|
|
"""
|
|
|
|
import logging
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
from slugify import slugify
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def generate_filename(title: str, date: str | None = None) -> str:
|
|
"""Generate a filename from title and optional date.
|
|
|
|
Args:
|
|
title: The note title to slugify.
|
|
date: Optional date string (YYYY-MM-DD). Uses today if not provided.
|
|
|
|
Returns:
|
|
Filename in format YYYY-MM-DD-slugified-title.md
|
|
"""
|
|
if date is None:
|
|
date = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
|
|
|
# Ensure date is just the date portion (handle ISO datetime strings)
|
|
date_part = date[:10] if len(date) >= 10 else date
|
|
|
|
slug = slugify(title, max_length=80)
|
|
if not slug:
|
|
slug = "untitled"
|
|
|
|
return f"{date_part}-{slug}.md"
|
|
|
|
|
|
def resolve_collision(target_dir: Path, filename: str) -> Path:
|
|
"""Resolve filename collisions by appending numeric suffix.
|
|
|
|
Args:
|
|
target_dir: Directory where the file will be written.
|
|
filename: Desired filename (e.g., 2024-03-15-meeting-notes.md).
|
|
|
|
Returns:
|
|
Full path with unique filename (appends -2, -3, etc. if needed).
|
|
"""
|
|
target = Path(target_dir) / filename
|
|
|
|
if not target.exists():
|
|
return target
|
|
|
|
# Split filename to insert suffix before .md
|
|
stem = filename.rsplit(".md", 1)[0]
|
|
suffix_num = 2
|
|
|
|
while True:
|
|
new_filename = f"{stem}-{suffix_num}.md"
|
|
new_target = Path(target_dir) / new_filename
|
|
if not new_target.exists():
|
|
logger.debug("Collision resolved: %s → %s", filename, new_filename)
|
|
return new_target
|
|
suffix_num += 1
|