make the test suite and openapi generator platform-independent

Windows checkouts turned LF into CRLF (core.autocrlf=true), and several
tests plus the openapi generator hardcoded LF or POSIX path separators.
The result was a suite that was green on Linux CI but red on Windows, and
an openapi.json whose /api/hermes/* routes silently disappeared when
generated on Windows.

Pin the repository to LF via .gitattributes, strip shebangs before
Vite's SSR transform, and key route files by their posix path. Add a
manually triggered macOS verification workflow so the same checks run
on a self-hosted macOS runner.
This commit is contained in:
2026-10-20 11:17:34 +08:00
committed by trae-solo-agent
parent 8052bf5781
commit a1fff482bf
20 changed files with 251 additions and 48 deletions
@@ -1,4 +1,5 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { resolve } from 'path'
const {
mockCopyFile,
@@ -41,14 +42,18 @@ describe('SafeFileStore backup fallback', () => {
const { SafeFileStore } = await import('../../packages/server/src/services/safe-file-store')
const store = new SafeFileStore()
// SafeFileStore.normalizePath() 走 resolve(),Windows 上 resolve('/tmp/config.yaml')
// = 'D:\tmp\config.yaml'。断言必须按生产语义写死,否则只在 Windows 上红。
const target = resolve('/tmp/config.yaml')
await store.writeText('/tmp/config.yaml', 'model:\n default: new\n', { backup: true })
expect(mockCopyFile).toHaveBeenCalledTimes(2)
expect(mockCopyFile).toHaveBeenNthCalledWith(1, '/tmp/config.yaml', '/tmp/config.yaml.bak')
expect(mockCopyFile.mock.calls[1][0]).toBe('/tmp/config.yaml')
expect(mockCopyFile.mock.calls[1][1]).toMatch(/^\/tmp\/config\.yaml\.bak\.\d+\./)
expect(mockWriteFile).toHaveBeenCalledWith(expect.stringContaining('/tmp/config.yaml.tmp.'), 'model:\n default: new\n', 'utf-8')
expect(mockRename).toHaveBeenCalledWith(expect.stringContaining('/tmp/config.yaml.tmp.'), '/tmp/config.yaml')
expect(mockCopyFile).toHaveBeenNthCalledWith(1, target, `${target}.bak`)
expect(mockCopyFile.mock.calls[1][0]).toBe(target)
expect(mockCopyFile.mock.calls[1][1].startsWith(`${target}.bak.`)).toBe(true)
expect(mockWriteFile).toHaveBeenCalledWith(expect.stringContaining(`${target}.tmp.`), 'model:\n default: new\n', 'utf-8')
expect(mockRename).toHaveBeenCalledWith(expect.stringContaining(`${target}.tmp.`), target)
})
it('preserves explicit backup path failures', async () => {