[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6X27HBWM6V81KXYW5XQSWFJ":3,"skill-same:01M6X27HBWM6V81KXYW5XQSWFJ":60},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":30,"linkOnly":31,"markdownContent":32,"markdownBody":33,"frontMatter":34,"refName":36,"commitSha":37,"skillDirectory":38,"forksCount":39,"repositoryHtmlUrl":40,"repositoryHomepageUrl":41,"ownerHtmlUrl":42,"ownerBlogUrl":43,"ownerDescription":44,"updatedAt":45,"install":46,"resources":59},"01M6X27HBWM6V81KXYW5XQSWFJ","windows-compatibility",null,"Cross-platform path handling and command patterns","github\u002Fsquad","github","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F9919?v=4","01M6AC83DS133TPXFSP1DHNCC6","GitHub","01M6X0MZ6B0WYMMDPK3Q61KER6",3382,"MIT","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Ftemplates\u002Fskills\u002Fwindows-compatibility\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29],"windows","windows compatibility","compatibility","git","command","patterns","cross-platform","platform","high","path","bugs","2026-11-10 10:12:30",false,"---\nname: \"windows-compatibility\"\ndescription: \"Cross-platform path handling and command patterns\"\ndomain: \"platform\"\nconfidence: \"high\"\nsource: \"earned (multiple Windows-specific bugs: colons in filenames, git -C failures, path separators)\"\n---\n\n## Context\n\nSquad 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.\n\n## Patterns\n\n### Filenames & Timestamps\n- **Never use colons in filenames:** ISO 8601 format `2026-03-15T05:30:00Z` is illegal on Windows\n- **Use `safeTimestamp()` utility:** Replaces colons with hyphens → `2026-03-15T05-30-00Z`\n- **Centralize formatting:** Don't inline `.toISOString().replace(\u002F:\u002Fg, '-')` — use the utility\n\n### Git Commands\n- **Never use `git -C {path}`:** Unreliable with Windows paths (backslashes, spaces, drive letters)\n- **Always `cd` first:** Change directory, then run git commands\n- **Check for changes before commit:** `git diff --cached --quiet` (exit 0 = no changes)\n\n### Commit Messages\n- **Never embed newlines in `-m` flag:** Backtick-n (`\\n`) fails silently in PowerShell\n- **Use temp file + `-F` flag:** Write message to file, commit with `git commit -F $msgFile`\n\n### Paths\n- **Never assume CWD is repo root:** Always use `TEAM ROOT` from spawn prompt or run `git rev-parse --show-toplevel`\n- **Use path.join() or path.resolve():** Don't manually concatenate with `\u002F` or `\\`\n\n### Path Comparison (Case Sensitivity)\n- **Never use naive prefix checks to confine paths:** a bare substring\u002Fprefix match can let sibling paths escape the intended root\n- **Never infer case-insensitive behavior from `process.platform` alone:** 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.\n- **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.\n- **Current implementation caveat:** This is the safe target pattern, not a claim about every existing repository implementation. `FSStorageProvider` currently folds case for all Darwin paths, so its root confinement is not volume-aware on case-sensitive macOS filesystems.\n- **Resolve first, compare second:** resolve both paths before comparing; do not compare user input or unresolved relative segments.\n- **Root confinement must be exact-match-or-separator:** a path is within `rootDir` only when it equals the normalized root exactly or starts with `rootDir + path.sep`; a bare substring\u002Fprefix match lets `\u002Froot-escape` slip past `\u002Froot`. Filesystem roots are valid roots and must remain exact-match-or-separator checks.\n- **Where it matters:** security checks such as path-traversal prevention, `rootDir` confinement, and any validation that a resolved path stays under an allowed directory\n- **Pattern:**\n  ```typescript\n  import path from 'node:path';\n\n  function normalizeForRootComparison(value: string, volumeIsCaseInsensitive = false): string {\n    return volumeIsCaseInsensitive ? value.toLowerCase() : value;\n  }\n\n  function isPathWithin(candidate: string, rootDir: string, volumeIsCaseInsensitive = false): boolean {\n    const a = normalizeForRootComparison(path.resolve(candidate), volumeIsCaseInsensitive);\n    const b = normalizeForRootComparison(path.resolve(rootDir), volumeIsCaseInsensitive);\n    const boundary = b.replace(\u002F[\\\\\u002F]+$\u002F, '') + path.sep;\n    return a === b || a.startsWith(boundary);\n  }\n  ```\n- **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\n\n### Repairing Stale LF-Pinned Working Trees\n\nAn `eol=lf` attribute affects checkout behavior; it does not repair files that were already\nmaterialized with CRLF. For the known shebang failure mode, use the repository's\n`scripts\u002Ffix-crlf-worktree.mjs` rather than a broad renormalization:\n\n1. Identify LF-pinned files that are CRLF on disk.\n2. Exclude files with a real content difference from the index.\n3. Rewrite only content-clean paths from the index with `git checkout-index -f`.\n4. Re-measure the complete repair set and report repaired, skipped, and remaining paths.\n\nThis is a local repair, not a source rewrite. Do not use `git add --renormalize .`; it rewrites\nthe index and creates unrelated line-ending churn. Do not force-checkout a locally modified file.\n\n## Examples\n\n✓ **Correct:**\n```powershell\n# Timestamp utility\n$safeTimestamp = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH-mm-ssZ')\n\n# Git workflow (PowerShell)\ncd $teamRoot\n# NEVER use `git add .squad\u002F` or broad globs — only stage files you intentionally changed\n# Stage only files you actually modified — use git status to build explicit list\n$filesToStage = git status --porcelain | Where-Object { $_.Length -gt 3 } | ForEach-Object { $_.Substring(3) -replace '^.* -> ','' } | Where-Object {\n  $_ -eq '.squad\u002Fdecisions.md' -or\n  $_ -eq '.squad\u002Fdecisions-archive.md' -or\n  $_ -like '.squad\u002Fagents\u002F*\u002Fhistory.md' -or\n  $_ -like '.squad\u002Fagents\u002F*\u002Fhistory-archive.md'\n}\nif ($filesToStage) { $filesToStage | Where-Object { $_ } | ForEach-Object { git add -- $_ } }\ngit diff --cached --quiet\nif ($LASTEXITCODE -ne 0) {\n  $msg = @\"\ndocs(ai-team): session log\n\nChanges:\n- Added decisions\n\"@\n  $msgFile = [System.IO.Path]::GetTempFileName()\n  Set-Content -Path $msgFile -Value $msg -Encoding utf8\n  git commit -F $msgFile\n  Remove-Item $msgFile\n}\n```\n\n✗ **Incorrect:**\n```javascript\n\u002F\u002F Colon in filename\nconst logPath = `.squad\u002Flog\u002F${new Date().toISOString()}.md`; \u002F\u002F ILLEGAL on Windows\n\n\u002F\u002F git -C with Windows path\nexec('git -C C:\\\\src\\\\squad add .squad\u002F'); \u002F\u002F UNRELIABLE\n\n\u002F\u002F Inline newlines in commit message\nexec('git commit -m \"First line\\nSecond line\"'); \u002F\u002F FAILS silently in PowerShell\n```\n\n## Anti-Patterns\n\n- Testing only on one platform (bugs ship to other platforms)\n- Assuming Unix-style paths work everywhere\n- Using `git -C` because it \"looks cleaner\" (it doesn't work)\n- Skipping `git diff --cached --quiet` check (creates empty commits)\n- Assuming all Darwin filesystems are case-insensitive for root-confinement checks\n","## Context\n\nSquad 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.\n\n## Patterns\n\n### Filenames & Timestamps\n- **Never use colons in filenames:** ISO 8601 format `2026-03-15T05:30:00Z` is illegal on Windows\n- **Use `safeTimestamp()` utility:** Replaces colons with hyphens → `2026-03-15T05-30-00Z`\n- **Centralize formatting:** Don't inline `.toISOString().replace(\u002F:\u002Fg, '-')` — use the utility\n\n### Git Commands\n- **Never use `git -C {path}`:** Unreliable with Windows paths (backslashes, spaces, drive letters)\n- **Always `cd` first:** Change directory, then run git commands\n- **Check for changes before commit:** `git diff --cached --quiet` (exit 0 = no changes)\n\n### Commit Messages\n- **Never embed newlines in `-m` flag:** Backtick-n (`\\n`) fails silently in PowerShell\n- **Use temp file + `-F` flag:** Write message to file, commit with `git commit -F $msgFile`\n\n### Paths\n- **Never assume CWD is repo root:** Always use `TEAM ROOT` from spawn prompt or run `git rev-parse --show-toplevel`\n- **Use path.join() or path.resolve():** Don't manually concatenate with `\u002F` or `\\`\n\n### Path Comparison (Case Sensitivity)\n- **Never use naive prefix checks to confine paths:** a bare substring\u002Fprefix match can let sibling paths escape the intended root\n- **Never infer case-insensitive behavior from `process.platform` alone:** 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.\n- **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.\n- **Current implementation caveat:** This is the safe target pattern, not a claim about every existing repository implementation. `FSStorageProvider` currently folds case for all Darwin paths, so its root confinement is not volume-aware on case-sensitive macOS filesystems.\n- **Resolve first, compare second:** resolve both paths before comparing; do not compare user input or unresolved relative segments.\n- **Root confinement must be exact-match-or-separator:** a path is within `rootDir` only when it equals the normalized root exactly or starts with `rootDir + path.sep`; a bare substring\u002Fprefix match lets `\u002Froot-escape` slip past `\u002Froot`. Filesystem roots are valid roots and must remain exact-match-or-separator checks.\n- **Where it matters:** security checks such as path-traversal prevention, `rootDir` confinement, and any validation that a resolved path stays under an allowed directory\n- **Pattern:**\n  ```typescript\n  import path from 'node:path';\n\n  function normalizeForRootComparison(value: string, volumeIsCaseInsensitive = false): string {\n    return volumeIsCaseInsensitive ? value.toLowerCase() : value;\n  }\n\n  function isPathWithin(candidate: string, rootDir: string, volumeIsCaseInsensitive = false): boolean {\n    const a = normalizeForRootComparison(path.resolve(candidate), volumeIsCaseInsensitive);\n    const b = normalizeForRootComparison(path.resolve(rootDir), volumeIsCaseInsensitive);\n    const boundary = b.replace(\u002F[\\\\\u002F]+$\u002F, '') + path.sep;\n    return a === b || a.startsWith(boundary);\n  }\n  ```\n- **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\n\n### Repairing Stale LF-Pinned Working Trees\n\nAn `eol=lf` attribute affects checkout behavior; it does not repair files that were already\nmaterialized with CRLF. For the known shebang failure mode, use the repository's\n`scripts\u002Ffix-crlf-worktree.mjs` rather than a broad renormalization:\n\n1. Identify LF-pinned files that are CRLF on disk.\n2. Exclude files with a real content difference from the index.\n3. Rewrite only content-clean paths from the index with `git checkout-index -f`.\n4. Re-measure the complete repair set and report repaired, skipped, and remaining paths.\n\nThis is a local repair, not a source rewrite. Do not use `git add --renormalize .`; it rewrites\nthe index and creates unrelated line-ending churn. Do not force-checkout a locally modified file.\n\n## Examples\n\n✓ **Correct:**\n```powershell\n# Timestamp utility\n$safeTimestamp = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH-mm-ssZ')\n\n# Git workflow (PowerShell)\ncd $teamRoot\n# NEVER use `git add .squad\u002F` or broad globs — only stage files you intentionally changed\n# Stage only files you actually modified — use git status to build explicit list\n$filesToStage = git status --porcelain | Where-Object { $_.Length -gt 3 } | ForEach-Object { $_.Substring(3) -replace '^.* -> ','' } | Where-Object {\n  $_ -eq '.squad\u002Fdecisions.md' -or\n  $_ -eq '.squad\u002Fdecisions-archive.md' -or\n  $_ -like '.squad\u002Fagents\u002F*\u002Fhistory.md' -or\n  $_ -like '.squad\u002Fagents\u002F*\u002Fhistory-archive.md'\n}\nif ($filesToStage) { $filesToStage | Where-Object { $_ } | ForEach-Object { git add -- $_ } }\ngit diff --cached --quiet\nif ($LASTEXITCODE -ne 0) {\n  $msg = @\"\ndocs(ai-team): session log\n\nChanges:\n- Added decisions\n\"@\n  $msgFile = [System.IO.Path]::GetTempFileName()\n  Set-Content -Path $msgFile -Value $msg -Encoding utf8\n  git commit -F $msgFile\n  Remove-Item $msgFile\n}\n```\n\n✗ **Incorrect:**\n```javascript\n\u002F\u002F Colon in filename\nconst logPath = `.squad\u002Flog\u002F${new Date().toISOString()}.md`; \u002F\u002F ILLEGAL on Windows\n\n\u002F\u002F git -C with Windows path\nexec('git -C C:\\\\src\\\\squad add .squad\u002F'); \u002F\u002F UNRELIABLE\n\n\u002F\u002F Inline newlines in commit message\nexec('git commit -m \"First line\\nSecond line\"'); \u002F\u002F FAILS silently in PowerShell\n```\n\n## Anti-Patterns\n\n- Testing only on one platform (bugs ship to other platforms)\n- Assuming Unix-style paths work everywhere\n- Using `git -C` because it \"looks cleaner\" (it doesn't work)\n- Skipping `git diff --cached --quiet` check (creates empty commits)\n- Assuming all Darwin filesystems are case-insensitive for root-confinement checks\n",{"name":5,"domain":26,"source":35,"confidence":27,"description":7},"earned (multiple Windows-specific bugs: colons in filenames, git -C failures, path separators)","dev","7b731ec97f35346bdc4fa87c3edaf16b808fc0ae","templates\u002Fskills\u002Fwindows-compatibility",518,"https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad","https:\u002F\u002Fgithub.github.io\u002Fsquad\u002F","https:\u002F\u002Fgithub.com\u002Fgithub","https:\u002F\u002Fgithub.com\u002Fabout","How people build software.","2026-11-13 01:58:30",{"source":8,"skillName":5,"commands":47,"prompt":57,"zipAvailable":58},[48,51,54],{"tool":49,"command":50},"npx","npx skills add github\u002Fsquad --skill windows-compatibility",{"tool":52,"command":53},"bunx","bunx skills add github\u002Fsquad --skill windows-compatibility",{"tool":55,"command":56},"pnpm","pnpm dlx skills add github\u002Fsquad --skill windows-compatibility","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Ftemplates\u002Fskills\u002Fwindows-compatibility\u002FSKILL.md",true,[],[61,69,76,83,115,127],{"skillNo":62,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":67,"publishedAt":68},"01M76742ST8ZMSD38226TH61CN","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.","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Fplugins\u002Fsquad\u002Fskills\u002Fsquad-coordinator-init-mode\u002FSKILL.md",[],[],"2026-11-12 13:55:43",{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":75,"publishedAt":68},"01M7673KYSME979M20YQTVV8P6","retro-enforcement","Keep retrospectives on schedule and track their action items as GitHub Issues, not markdown checklists","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Fplugins\u002Fsquad\u002Fskills\u002Fretro-enforcement\u002FSKILL.md",[],[],{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":82,"publishedAt":68},"01M7670QCHBSR4W2XSX8XPA2ZB","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","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Fplugins\u002Fsquad\u002Fskills\u002Fcli-wiring\u002FSKILL.md",[],[],{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":94,"publishedAt":30},"01M6X287DVJK1S91END9DSHETN","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.","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Fworkflows\u002Fskills\u002Fgh-aw-enlistment\u002FSKILL.md",[89],{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114],"gh aw enlistment","gh","preflight","guide","identity","compiling","squad","pr creation","Safety","safe","update","human","github cli","lock","workflows","auto","files","agentic workflows","ci","actions",{"skillNo":116,"name":117,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":121,"publishedAt":30},"01M6X27Y5119CSRQFFJCV6432R","My Skill","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Ftest-fixtures\u002Fskills-test-abb30454\u002Fmy-skill\u002FSKILL.md",[120],{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},[122,123,124,125,126],"my","my skill","tester","testing","vitest",{"skillNo":128,"name":129,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":133,"publishedAt":30},"01M6X27RWAYB2X9ER0MVRRKXGA","bad-skill","https:\u002F\u002Fgithub.com\u002Fgithub\u002Fsquad\u002Fblob\u002Fdev\u002Ftest-fixtures\u002Fskills-test-abb30454\u002Fbad-skill\u002FSKILL.md",[132],{"categoryNo":90,"categoryName":91,"taxonomyType":92,"taxonomyTypeDesc":93},[134,135],"bad","bad skill"]