diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-26 01:56:14 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-26 01:56:14 -0500 |
| commit | 98382929852b213f8dc8b1ba720cc0d1861159b6 (patch) | |
| tree | 004d12d6ddfc21af0c999a6faca8f00332ed4f8d /.ai/scripts/inbox-send.py | |
| parent | 8abcc1adc40b0609d3af58aedf003344209e3ad2 (diff) | |
| download | rulesets-98382929852b213f8dc8b1ba720cc0d1861159b6.tar.gz rulesets-98382929852b213f8dc8b1ba720cc0d1861159b6.zip | |
fix(inbox-send): preserve dots in copied filenames
send_file ran filenames through slugify(), which flattens dots to hyphens. That corrupts the engine.plugin.org plugin-namespace convention: triage-intake.personal-gmail.org arrived as triage-intake-personal-gmail.org, which breaks the engine's triage-intake.*.org glob and the routing that depends on the first dot.
I added slugify_filename() for filename stems. It keeps dots, hyphens, underscores, and case, collapses only whitespace runs to hyphens, and truncates on a separator boundary. The prose --text path still uses slugify().
Diffstat (limited to '.ai/scripts/inbox-send.py')
| -rw-r--r-- | .ai/scripts/inbox-send.py | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/.ai/scripts/inbox-send.py b/.ai/scripts/inbox-send.py index 8e650ff..5373bd4 100644 --- a/.ai/scripts/inbox-send.py +++ b/.ai/scripts/inbox-send.py @@ -110,6 +110,32 @@ def slugify(text: str, max_length: int = MAX_SLUG_LENGTH) -> str: return truncated.strip().replace(" ", "-") +def slugify_filename(stem: str, max_length: int = MAX_SLUG_LENGTH) -> str: + """Slugify a filename stem while preserving its structure. + + Unlike slugify() (for freeform prose), a filename stem is already + filename-safe and carries meaning in its separators — dots especially. + The engine.plugin.org plugin-namespace convention encodes the + engine/plugin boundary in the first dot, so flattening dots to hyphens + corrupts the name. Keep [A-Za-z0-9._-] and case (e.g. the TOOLARGE- + prefix convention), turn whitespace runs into single hyphens, drop + anything else. + """ + stem = re.sub(r"\s+", "-", stem.strip()) + stem = re.sub(r"[^A-Za-z0-9._-]+", "", stem) + stem = re.sub(r"-{2,}", "-", stem).strip("-._") + if not stem: + return "" + if len(stem) <= max_length: + return stem + truncated = stem[:max_length] + # Walk back to the last separator so truncation doesn't cut mid-segment. + last_sep = max(truncated.rfind("-"), truncated.rfind("."), truncated.rfind("_")) + if last_sep > 0: + truncated = truncated[:last_sep] + return truncated.strip("-._") + + def find_target(target_name: str, projects: list[Path]) -> Path | None: """Resolve `target_name` against the project list (basename or numeric index).""" if target_name.isdigit(): @@ -163,7 +189,7 @@ def send_file( """Copy src_path into target_inbox with a dated, source-tagged name.""" if not src_path.is_file(): raise FileNotFoundError(f"source file not found: {src_path}") - slug = custom_name or slugify(src_path.stem) + slug = custom_name or slugify_filename(src_path.stem) if not slug: raise ValueError(f"could not derive a slug from file: {src_path}") ext = src_path.suffix |
