aboutsummaryrefslogtreecommitdiff
path: root/.ai/scripts/inbox-send.py
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-23 23:57:58 -0500
committerCraig Jennings <c@cjennings.net>2026-07-23 23:57:58 -0500
commita053e9d1ecbf583b4a6f054c34f64ad1f359365e (patch)
tree27d60e5b02df6fdfad8094886c08952c82d5c70f /.ai/scripts/inbox-send.py
parent0f91a8e0cd0a4b5b351efe407987bb8bb6ab125e (diff)
downloadrulesets-a053e9d1ecbf583b4a6f054c34f64ad1f359365e.tar.gz
rulesets-a053e9d1ecbf583b4a6f054c34f64ad1f359365e.zip
fix(inbox-send): clean error on an unreadable source, dedupe overlapping roots
main caught ValueError and FileNotFoundError around the send, so an unreadable source raised a PermissionError as a raw traceback instead of the clean "inbox-send: <message>" every other failure produces. Widening the catch to OSError covers the unreadable source, the missing source, and any atomic-write failure alike. discover_projects appended without deduping, so a roots config naming both a parent directory and one of its children listed the same project at two indices. It now dedupes on the resolved path, first-seen order preserved.
Diffstat (limited to '.ai/scripts/inbox-send.py')
-rwxr-xr-x.ai/scripts/inbox-send.py20
1 files changed, 17 insertions, 3 deletions
diff --git a/.ai/scripts/inbox-send.py b/.ai/scripts/inbox-send.py
index 5787a84..663efcb 100755
--- a/.ai/scripts/inbox-send.py
+++ b/.ai/scripts/inbox-send.py
@@ -70,17 +70,28 @@ def discover_projects(roots: list[Path]) -> list[Path]:
a specific project root (included directly if it qualifies).
"""
projects: list[Path] = []
+ seen: set[Path] = set()
+
+ def _add(p: Path) -> None:
+ # Dedupe on the resolved path: a roots config naming both a parent and
+ # one of its children would otherwise list the child project twice, at
+ # two different indices.
+ key = p.resolve()
+ if key not in seen:
+ seen.add(key)
+ projects.append(p)
+
for root in roots:
if not root.is_dir():
continue
if _is_project(root):
- projects.append(root)
+ _add(root)
continue
for child in sorted(root.iterdir()):
if not child.is_dir():
continue
if _is_project(child):
- projects.append(child)
+ _add(child)
return projects
@@ -345,7 +356,10 @@ def main() -> int:
else:
assert args.file is not None
dest = send_file(target_inbox, args.file, source_name, args.name, now)
- except (ValueError, FileNotFoundError) as exc:
+ except (ValueError, OSError) as exc:
+ # OSError covers FileNotFoundError (missing source), PermissionError
+ # (unreadable source), and any atomic-write failure — all should
+ # surface as the clean "inbox-send: <message>" error, never a traceback.
print(f"inbox-send: {exc}", file=sys.stderr)
return 1