Skip to content

Commit 723ec5c

Browse files
committed
lock line endings and expand Windows lint to .ps1
Cross-platform audit for medical-grade rigor: - Add .gitattributes with explicit eol=crlf for .bat/.cmd/.ps1 so a Mac contributor's commit can't silently strip CR bytes and break start.bat / start-local-agent.ps1 on Windows. .command / .sh are pinned to LF since macOS double-clicks on them. - Strip em dash from start-local-agent.ps1 (added in an earlier commit). Windows PowerShell 5.1 can't read BOM-less UTF-8 reliably, so Windows launcher scripts follow the same ASCII rule as .bat. - Extend the Windows CI lint to cover scripts/dev/*.ps1 and scripts/windows/*.ps1 with the same ASCII / CRLF / NUL checks.
1 parent bef3f0d commit 723ec5c

3 files changed

Lines changed: 55 additions & 14 deletions

File tree

.gitattributes

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Default: let Git decide (text auto-detect, normalize to LF in repo).
2+
* text=auto
3+
4+
# Windows launchers MUST stay CRLF regardless of client core.autocrlf.
5+
# cmd.exe is picky about line endings, and PowerShell on Windows expects
6+
# them too. Without this, a Mac contributor's commit can silently strip
7+
# CR bytes and break start.bat on every Windows machine.
8+
*.bat text eol=crlf
9+
*.cmd text eol=crlf
10+
*.ps1 text eol=crlf
11+
12+
# macOS / Linux launchers MUST stay LF. Double-click .command files break
13+
# on macOS if they ever get CRLF endings.
14+
*.command text eol=lf
15+
*.sh text eol=lf
16+
17+
# Binary types - never touch.
18+
*.png binary
19+
*.jpg binary
20+
*.jpeg binary
21+
*.gif binary
22+
*.ico binary
23+
*.pdf binary
24+
*.zip binary
25+
*.tar binary
26+
*.gz binary
27+
*.node binary

.github/workflows/windows-smoke.yml

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,42 +26,56 @@ jobs:
2626
shell: pwsh
2727
run: npm ci
2828

29-
- name: Lint .bat launchers
29+
- name: Lint Windows launchers (.bat / .ps1)
3030
shell: pwsh
3131
run: |
3232
$ErrorActionPreference = "Stop"
33-
$bats = @("start.bat", "stop.bat")
33+
$targets = @(
34+
"start.bat", "stop.bat",
35+
"scripts/dev/start-local-agent.ps1",
36+
"scripts/dev/stop-local-agent.ps1",
37+
"scripts/windows/capture-screen.ps1"
38+
)
3439
$failed = $false
35-
foreach ($bat in $bats) {
36-
$bytes = [System.IO.File]::ReadAllBytes($bat)
40+
foreach ($target in $targets) {
41+
if (-not (Test-Path $target)) {
42+
Write-Host "skip missing: $target"
43+
continue
44+
}
45+
$bytes = [System.IO.File]::ReadAllBytes($target)
3746
$text = [System.Text.Encoding]::ASCII.GetString($bytes)
3847
39-
# 1. Pure ASCII (no UTF-8 multi-byte sequences that would
40-
# be misread under Chinese Windows code page 936).
48+
# 1. Pure ASCII. cmd.exe on zh-CN runs code page 936 and will
49+
# misdecode UTF-8 multi-byte sequences in .bat files,
50+
# producing '文件名、目录名或卷标语法不正确'. Applying the
51+
# same rule to .ps1 keeps us consistent and protects
52+
# Windows PowerShell 5.1 hosts that can't read BOM-less
53+
# UTF-8 reliably.
4154
foreach ($b in $bytes) {
4255
if ($b -gt 0x7f) {
43-
Write-Error "$bat contains non-ASCII byte 0x$("{0:X2}" -f $b) — cmd.exe on zh-CN will fail to parse it"
56+
Write-Error "$target contains non-ASCII byte 0x$("{0:X2}" -f $b) - use ASCII-only for Windows compatibility"
4457
$failed = $true
4558
break
4659
}
4760
}
4861
49-
# 2. CRLF line endings — LF-only .bat files misbehave on some
50-
# cmd.exe versions.
62+
# 2. CRLF line endings. LF-only .bat files confuse some cmd.exe
63+
# versions, and Windows PowerShell 5.1 parses CRLF more
64+
# reliably than LF.
5165
if ($text -notmatch "`r`n") {
52-
Write-Error "$bat has no CRLF line endings"
66+
Write-Error "$target has no CRLF line endings"
5367
$failed = $true
5468
}
5569
56-
# 3. No Unix-style /dev/null redirection cmd.exe would create
70+
# 3. No Unix-style /dev/null redirection. cmd.exe would create
5771
# an actual file named 'null' under a 'dev' directory.
5872
if ($text -match "/dev/null") {
59-
Write-Error "$bat contains Unix-style '/dev/null' use 'NUL' instead"
73+
Write-Error "$target contains Unix-style '/dev/null' - use 'NUL' instead"
6074
$failed = $true
6175
}
6276
}
6377
if ($failed) { exit 1 }
64-
Write-Host "All .bat files passed ASCII / CRLF / NUL lint."
78+
Write-Host "All Windows launchers passed ASCII / CRLF / NUL lint."
6579
6680
- name: Run start.bat end-to-end
6781
shell: cmd

scripts/dev/start-local-agent.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ $process = Start-Process `
219219
-WindowStyle Hidden `
220220
-PassThru
221221

222-
# Do NOT write $process.Id to $PidFile here $process is the launcher
222+
# Do NOT write $process.Id to $PidFile here - $process is the launcher
223223
# PowerShell wrapper, not the node agent. server.ts writes its own real
224224
# PID once it binds the port. Writing the wrapper PID makes the agent's
225225
# ensureSingleInstance() see a "live" PID and exit immediately.

0 commit comments

Comments
 (0)