fix(gen-skill-docs): stop the catalog trim chopping descriptions at embedded periods

The description-trim regex treated the first period as end-of-sentence, so
skill descriptions with embedded periods (e.g. file extensions, version
numbers) truncated mid-thought in the generated catalog — the discovery
surface every host loads. Trim now respects the full first sentence;
diagram's description regenerates to its intended text.

Contributed by @sneakygriff (PR #2171).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-14 20:20:55 -07:00
co-authored by Claude Fable 5
parent e6dfc46e7a
commit 0c4b5ac6a9
7 changed files with 70 additions and 38 deletions
+8 -4
View File
@@ -323,12 +323,16 @@ export function splitCatalogDescription(description: string): CatalogParts {
const hasGstackTag = /\(gstack\)/.test(working);
if (hasGstackTag) working = working.replace(/\(gstack\)/, '').trim();
// Lead = first sentence (up to first period followed by space or end of string).
// We tolerate sentences with embedded periods (URLs, "v1.45.0.0") by requiring
// the period to be followed by whitespace OR end-of-text.
// Lead = first sentence, ending at the first `.`/`!`/`?` that is followed by
// whitespace or end-of-text. Terminator chars NOT followed by whitespace/end
// (embedded periods in "TODOS.md", URLs, "v1.45.0.0") are consumed by the
// second alternative `[.!?](?!\s|$)` and do NOT end the sentence. The two
// alternatives are disjoint character classes, so there is no ambiguity and
// no catastrophic-backtracking risk. If no terminator-followed-by-boundary
// exists at all, we fall back to a 20-word cut below.
// First normalize to single-line for sentence detection, then back out.
const collapsed = working.replace(/\s+/g, ' ').trim();
const sentenceMatch = collapsed.match(/^([^.!?]*[.!?])(?:\s|$)/);
const sentenceMatch = collapsed.match(/^((?:[^.!?]|[.!?](?!\s|$))*[.!?])(?:\s|$)/);
// sentenceLead is the FULL first sentence (no truncation). We compute routing
// from this position, then optionally truncate the displayed lead afterwards.
// Truncating first then computing routing was the v1.45.0.0 bug — when the
+4 -4
View File
@@ -79,8 +79,8 @@
"voice_line": "Voice triggers (speech-to-text aliases): \"dx audit\", \"test the developer experience\", \"try the onboarding\", \"developer experience test\"."
},
"diagram": {
"lead": "Turn an English description (or mermaid source) into a diagram triplet: the source, an editable .excalidraw file you can open",
"routing": "on excalidraw.com,\nand rendered SVG + PNG (clean mermaid style; the .excalidraw carries the\nhand-drawn aesthetic). Fully offline.\nUse when asked to \"make a diagram\", \"draw the architecture\", \"create a\nflowchart\", \"diagram this\", or \"visualize this flow\".",
"lead": "Turn an English description (or mermaid source) into a diagram triplet: the source, an editable .excalidraw file you can open on excalidraw.com, and rendered SVG + PNG.",
"routing": "The SVG/PNG use clean mermaid style; the\n.excalidraw carries the hand-drawn aesthetic. Fully offline.\nUse when asked to \"make a diagram\", \"draw the architecture\", \"create a\nflowchart\", \"diagram this\", or \"visualize this flow\".",
"voice_line": null
},
"document-generate": {
@@ -264,8 +264,8 @@
"voice_line": null
},
"sync-gbrain": {
"lead": "Keep gbrain current with this repo's code and refresh agent search guidance in CLAUDE.md. Wraps the gstack-gbrain-sync orchestrator with state",
"routing": "probing, native code-surface registration, capability checks,\nand a verdict block. Re-runnable, idempotent. Use when: \"sync gbrain\",\n\"refresh gbrain\", \"re-index this repo\", \"gbrain search isn't finding\nthings\".",
"lead": "Keep gbrain current with this repo's code and refresh agent search guidance in CLAUDE.md.",
"routing": "Wraps the gstack-gbrain-sync orchestrator with\nstate probing, native code-surface registration, capability checks,\nand a verdict block. Re-runnable, idempotent. Use when: \"sync gbrain\",\n\"refresh gbrain\", \"re-index this repo\", \"gbrain search isn't finding\nthings\".",
"voice_line": null
},
"unfreeze": {