mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-31 04:07:52 +00:00
fix(skills): extend CRLF fence handling to stripFrontmatter + derived-manifest name parse
Same root cause as the parent commit, two sibling LF-only fence regexes: - src/core/skill-brain-first.ts FRONTMATTER_RE: on CRLF skills, stripFrontmatter was a no-op, so a frontmatter 'tools: [web_search]' leaked into the body scan and false-flagged the skill (the exact F6 case the code comments guard against). Regression test added. - src/core/skill-manifest.ts parseSkillName: derived-manifest mode (no manifest.json) fell back to the dirname for CRLF skills instead of the frontmatter name. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
6f52ee8321
commit
e45566d0e8
@@ -162,9 +162,11 @@ export const PHASE_HEADING_RE = /^##+\s*(?:Phase\s*1|Step\s*0)\b[^\n]*brain/im;
|
||||
/**
|
||||
* Frontmatter fence regex used by body extraction. Conservative match:
|
||||
* leading `---\n` through the next `\n---` (greedy stop). Matches the
|
||||
* shape `parseSkillFrontmatter` already accepts.
|
||||
* shape `parseSkillFrontmatter` already accepts, including CRLF fences —
|
||||
* if this stayed LF-only, a CRLF skill's `tools: [web_search]` frontmatter
|
||||
* would survive into the body scan and false-flag the skill (F6).
|
||||
*/
|
||||
const FRONTMATTER_RE = /^---\n[\s\S]*?\n---\n?/;
|
||||
const FRONTMATTER_RE = /^---\r?\n[\s\S]*?\r?\n---\r?\n?/;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Hardcoded EXEMPT_SKILLS (CMT1 — replaces the dropped upgrade migration)
|
||||
|
||||
@@ -47,7 +47,7 @@ export interface ManifestLoadResult {
|
||||
function parseSkillName(skillMdPath: string): string | null {
|
||||
try {
|
||||
const content = readFileSync(skillMdPath, 'utf-8');
|
||||
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
||||
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
||||
if (!fmMatch) return null;
|
||||
const fm = fmMatch[1];
|
||||
// Match `name: foo` or `name: "foo"` or `name: 'foo'`
|
||||
|
||||
@@ -227,6 +227,20 @@ describe('stripFrontmatter', () => {
|
||||
// Body should NOT contain `web_search` (it was in the stripped frontmatter).
|
||||
expect(body.includes('web_search')).toBe(false);
|
||||
});
|
||||
|
||||
test('F6 holds for CRLF fences — frontmatter tools do not leak into the body scan', () => {
|
||||
const content = [
|
||||
'---',
|
||||
'name: x',
|
||||
'tools: [web_search]',
|
||||
'---',
|
||||
'',
|
||||
'# x',
|
||||
'Body says gbrain search comes first.',
|
||||
].join('\r\n');
|
||||
const body = stripFrontmatter(content);
|
||||
expect(body.includes('web_search')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('offset helpers', () => {
|
||||
|
||||
Reference in New Issue
Block a user