mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-11 23:49:01 +02:00
Merge remote-tracking branch 'origin/main' into garrytan/gbrain-code-smell-audit
# Conflicts: # CHANGELOG.md # browse/test/dual-listener.test.ts # browse/test/fixtures/security-bench-haiku-responses.json # browse/test/sidebar-tabs.test.ts # browse/test/sidebar-ux.test.ts # browse/test/terminal-agent.test.ts # claude/SKILL.md.tmpl # scripts/gen-skill-docs.ts # scripts/proactive-suggestions.json # spec/SKILL.md # test/gen-skill-docs.test.ts # test/host-config.test.ts
This commit is contained in:
@@ -317,12 +317,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
|
||||
@@ -793,7 +797,14 @@ function processExternalHost(
|
||||
}
|
||||
|
||||
function processTemplate(tmplPath: string, host: Host = 'claude'): { outputPath: string; content: string; symlinkLoop?: boolean } {
|
||||
const tmplContent = fs.readFileSync(tmplPath, 'utf-8');
|
||||
// Normalize to LF at the entry point. Templates may have CRLF on disk when
|
||||
// checked out on Windows with core.autocrlf=true. Downstream regexes
|
||||
// (processVoiceTriggers, transformFrontmatter) hardcode \n, so without
|
||||
// normalization they silently no-op on CRLF — producing different output
|
||||
// than CI (Linux, LF) and breaking the Skill Docs Freshness check.
|
||||
// (catalogParts left the return type with the proactive-suggestions
|
||||
// retirement — merge of the two v1.64 waves.)
|
||||
const tmplContent = fs.readFileSync(tmplPath, 'utf-8').replace(/\r\n/g, '\n');
|
||||
const relTmplPath = path.relative(ROOT, tmplPath);
|
||||
let outputPath = tmplPath.replace(/\.tmpl$/, '');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user