Skip to content

fix: keep the tree on LF, and stop refusing a skill over its line endings - #332

Open
L4XB wants to merge 1 commit into
every-app:mainfrom
L4XB:fix/331-lf-checkout-and-crlf-tolerant-frontmatter
Open

L4XB wants to merge 1 commit into
every-app:mainfrom
L4XB:fix/331-lf-checkout-and-crlf-tolerant-frontmatter

Conversation

@L4XB

@L4XB L4XB commented Sep 14, 2026 •

Copy link
Copy Markdown

Refs #331.

Two things, because the issue has two halves

The tree. There is no .gitattributes, so Git's core.autocrlf=true Windows default checks every text file out with CRLF. On that tree SKILL.md starts ---\r\n and every skill fails to parse; prettier --check reports the same tree, its endOfLine default being lf. Linux CI never sees either, and each Windows contributor hits it independently. * text=auto eol=lf fixes the checkout, which is the direction the issue suggests.

The parser. .gitattributes only helps trees cloned or renormalised after it lands — an existing Windows checkout keeps the endings it already has. And separately from Windows: refusing a well-formed skill because of its line endings is a defect on its own terms, so parseSkill now accepts \r?\n at both delimiters.

Either half alone leaves a real case broken, which is why both are here.

On the binary declarations

text=auto keeps Git's own binary detection, and eol=lf then applies to what it decides is text. I declared the binary extensions explicitly anyway (48 such files in the tree) because a detection heuristic that guesses wrong there corrupts the file, where the same mistake on a text file merely reformats it. Verified with git check-attr:

src/server/features/sam/samSkills.ts:  text: auto   eol: lf
.agents/skills/competitive-landscape/SKILL.md:  text: auto   eol: lf
badseo/public/openseo-logo.png:  binary: set

No .bat / .cmd / .ps1 in the tree, so nothing needs to keep CRLF.

The anchors stay

The widened pattern is /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/ — still anchored at the start of the file, still requiring the delimiters on their own lines. \r?\n widens which line endings are accepted, not which files are. There is a cell for that: a markdown horizontal rule in the body must not be mistaken for frontmatter.

parseSkill is now exported so the tests can reach it; buildSamSkillSource bundles the repo's own skills through import.meta.glob at build time, so there is no way to hand it a CRLF file from outside.

Tests

Four new cells in samSkills.test.ts, checked against mutants:

mutation killed by
back to the LF-only pattern (the bug) parses a skill checked out with CRLF endings
drop the anchors while widening does not mistake a horizontal rule in the body for frontmatter
tolerate CR at the opening delimiter but not the closing one parses a skill checked out with CRLF endings

still parses LF endings and still refuses a file with no frontmatter, CRLF or not are the accept controls.

$ npx vitest run src/server
Test Files  109 passed (109)
     Tests  809 passed (809)

$ npx prettier --check src/
All matched files use Prettier code style!

$ npx tsc --noEmit
(clean)

I could not run this on Windows — no Windows machine here — so the CRLF cases are driven by building the string with \r\n rather than by a real checkout. The .gitattributes half is verified with git check-attr rather than by re-cloning.

…ings

With no `.gitattributes`, Git's `core.autocrlf=true` Windows default checks
every text file out with CRLF. On that tree `SKILL.md` starts `---\r\n`,
the frontmatter pattern matched `---\n` only, and every skill failed to
parse -- `Skill has no frontmatter`, on files that are perfectly well
formed. `prettier --check` reports the same tree for the same reason, its
`endOfLine` default being `lf`. Linux CI never sees either.

`.gitattributes` declares `* text=auto eol=lf`, so a fresh clone produces
a working tree the suite and the formatter pass on with no per-machine Git
configuration. Binary extensions are declared rather than detected: a
heuristic that guesses wrong there corrupts the file instead of merely
reformatting it.

The parser accepts `\r?\n` at both delimiters as well. `.gitattributes`
only fixes trees that are cloned or renormalised after it lands, and an
existing Windows checkout keeps the endings it already has -- and refusing
a well-formed skill over its line endings is a defect on its own terms.
The delimiters stay anchored: the frontmatter block must still start the
file and sit on its own lines, so a horizontal rule in the body is not
mistaken for it.

Refs every-app#331
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant