The catalog-description splitter used the sentence regex
`^([^.!?]*[.!?])(?:\s|$)` to find the lead (first) sentence. The `[^.!?]*`
class is greedy and cannot backtrack across a period, so any first sentence
containing an embedded terminator — "TODOS.md" / "CLAUDE.md", a URL, or a
version number like "v1.45.0.0" — failed to match a real sentence boundary.
When the match failed, the code silently fell back to a blind 20-word cut,
producing leads that either stopped mid-token or ran past the true sentence
end into the next clause.
The fix rewrites the lead regex to
`^((?:[^.!?]|[.!?](?!\s|$))*[.!?])(?:\s|$)`: a terminator that is NOT followed
by whitespace/end-of-text (an embedded period) is consumed by the second,
disjoint alternative and no longer ends the sentence, while a terminator
followed by a boundary still closes the lead. The two alternatives cover
disjoint inputs, so there is no ambiguity or catastrophic-backtracking risk.
Adds regression coverage in test/catalog-trim.test.ts for embedded periods,
URLs, and a >200-char first sentence with embedded periods (ellipsis path,
not the word-count fallback).
Re-renders the two skill descriptions that were previously mis-split:
- diagram: lead now runs to "...and rendered SVG + PNG." instead of
truncating at "you can open".
- sync-gbrain: lead now stops at "...guidance in CLAUDE.md." instead of
spilling the next clause in via the 20-word fallback.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>