windows-compatibility
Cross-platform path handling and command patterns
- License 许可
- MIT
- 所属仓库
- github/squad
- 最近更新
- 2026-11-13
- Stars
- ★ 3.4k
- Forks
- 518
01 前言 Front Matter
- name
- windows-compatibility
- domain
- platform
- source
- earned (multiple Windows-specific bugs: colons in filenames, git -C failures, path separators)
- confidence
- high
- description
- Cross-platform path handling and command patterns
03 SKILL.md 正文
Context
Squad runs on Windows, macOS, and Linux. Several bugs have been traced to platform-specific assumptions: ISO timestamps with colons (illegal on Windows), git -C with Windows paths (unreliable), forward-slash paths in Node.js on Windows.
Patterns
Filenames & Timestamps
- Never use colons in filenames: ISO 8601 format
2026-03-15T05:30:00Zis illegal on Windows - Use
safeTimestamp()utility: Replaces colons with hyphens →2026-03-15T05-30-00Z - Centralize formatting: Don't inline
.toISOString().replace(/:/g, '-')— use the utility
Git Commands
- Never use
git -C {path}: Unreliable with Windows paths (backslashes, spaces, drive letters) - Always
cdfirst: Change directory, then run git commands - Check for changes before commit:
git diff --cached --quiet(exit 0 = no changes)
Commit Messages
- Never embed newlines in
-mflag: Backtick-n (\n) fails silently in PowerShell - Use temp file +
-Fflag: Write message to file, commit withgit commit -F $msgFile
Paths
- Never assume CWD is repo root: Always use
TEAM ROOTfrom spawn prompt or rungit rev-parse --show-toplevel - Use path.join() or path.resolve(): Don't manually concatenate with
/or\
Path Comparison (Case Sensitivity)
- Never use naive prefix checks to confine paths: a bare substring/prefix match can let sibling paths escape the intended root
- Never infer case-insensitive behavior from
process.platformalone: Windows is case-insensitive, but Darwin volumes are not all case-insensitive. APFS and HFS+ can be case-sensitive; a blanket lowercase conversion on macOS can conflate distinct sibling directories. - Use filesystem-aware case handling: Only fold case when the relevant volume has been explicitly identified as case-insensitive. Otherwise, compare the resolved path case-sensitively.
- Current implementation caveat: This is the safe target pattern, not a claim about every existing repository implementation.
FSStorageProvidercurrently folds case for all Darwin paths, so its root confinement is not volume-aware on case-sensitive macOS filesystems. - Resolve first, compare second: resolve both paths before comparing; do not compare user input or unresolved relative segments.
- Root confinement must be exact-match-or-separator: a path is within
rootDironly when it equals the normalized root exactly or starts withrootDir + path.sep; a bare substring/prefix match lets/root-escapeslip past/root. Filesystem roots are valid roots and must remain exact-match-or-separator checks. - Where it matters: security checks such as path-traversal prevention,
rootDirconfinement, and any validation that a resolved path stays under an allowed directory - Pattern:
import path from 'node:path'; function normalizeForRootComparison(value: string, volumeIsCaseInsensitive = false): string { return volumeIsCaseInsensitive ? value.toLowerCase() : value; } function isPathWithin(candidate: string, rootDir: string, volumeIsCaseInsensitive = false): boolean { const a = normalizeForRootComparison(path.resolve(candidate), volumeIsCaseInsensitive); const b = normalizeForRootComparison(path.resolve(rootDir), volumeIsCaseInsensitive); const boundary = b.replace(/[\\/]+$/, '') + path.sep; return a === b || a.startsWith(boundary); } - Resolve first, compare second: compare normalized absolute paths; only treat a case mismatch as equivalent when the relevant filesystem volume has already been confirmed to be case-insensitive
Repairing Stale LF-Pinned Working Trees
An eol=lf attribute affects checkout behavior; it does not repair files that were already
materialized with CRLF. For the known shebang failure mode, use the repository's
scripts/fix-crlf-worktree.mjs rather than a broad renormalization:
- Identify LF-pinned files that are CRLF on disk.
- Exclude files with a real content difference from the index.
- Rewrite only content-clean paths from the index with
git checkout-index -f. - Re-measure the complete repair set and report repaired, skipped, and remaining paths.
This is a local repair, not a source rewrite. Do not use git add --renormalize .; it rewrites
the index and creates unrelated line-ending churn. Do not force-checkout a locally modified file.
Examples
✓ Correct:
# Timestamp utility
$safeTimestamp = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH-mm-ssZ')
# Git workflow (PowerShell)
cd $teamRoot
# NEVER use `git add .squad/` or broad globs — only stage files you intentionally changed
# Stage only files you actually modified — use git status to build explicit list
$filesToStage = git status --porcelain | Where-Object { $_.Length -gt 3 } | ForEach-Object { $_.Substring(3) -replace '^.* -> ','' } | Where-Object {
$_ -eq '.squad/decisions.md' -or
$_ -eq '.squad/decisions-archive.md' -or
$_ -like '.squad/agents/*/history.md' -or
$_ -like '.squad/agents/*/history-archive.md'
}
if ($filesToStage) { $filesToStage | Where-Object { $_ } | ForEach-Object { git add -- $_ } }
git diff --cached --quiet
if ($LASTEXITCODE -ne 0) {
$msg = @"
docs(ai-team): session log
Changes:
- Added decisions
"@
$msgFile = [System.IO.Path]::GetTempFileName()
Set-Content -Path $msgFile -Value $msg -Encoding utf8
git commit -F $msgFile
Remove-Item $msgFile
}
✗ Incorrect:
// Colon in filename
const logPath = `.squad/log/${new Date().toISOString()}.md`; // ILLEGAL on Windows
// git -C with Windows path
exec('git -C C:\\src\\squad add .squad/'); // UNRELIABLE
// Inline newlines in commit message
exec('git commit -m "First line\nSecond line"'); // FAILS silently in PowerShell
Anti-Patterns
- Testing only on one platform (bugs ship to other platforms)
- Assuming Unix-style paths work everywhere
- Using
git -Cbecause it "looks cleaner" (it doesn't work) - Skipping
git diff --cached --quietcheck (creates empty commits) - Assuming all Darwin filesystems are case-insensitive for root-confinement checks
04 同仓库更多 Skills
squad-coordinator-init-mode
Squad coordinator only: Init Mode, proposing and casting a new team. Load when team.md is missing or has an empty roster, or when asked to set up or cast a team.
retro-enforcement
Keep retrospectives on schedule and track their action items as GitHub Issues, not markdown checklists
cli-wiring
Checklist for wiring a new Squad CLI command: route it in cli-entry.ts, add help text, and test that it is reachable
gh-aw-enlistment
Enlist a repository into Squad by installing the supported GitHub Agentic Workflows (gh-aw) bootstrap — with strict compilation, an explicit safe-update allowlist, and a human-reviewed bootstrap PR. Never auto-merges.
My Skill
暂无简介
bad-skill
暂无简介