$ErrorActionPreference = "Stop" & powershell -ExecutionPolicy Bypass -File scripts/dev/windows/check-workspace.ps1 $expectedOrigin = "ssh://git@git.txyundm.cn:2222/panda/qipai.git" $requiredPaths = @( "V5.0.md", "V4.8.md", "setup.sh", "deploy/README.md", "deploy/VERSION", "docs/current-baseline.md", "README.md", "V5.1.md", "V5.2.md", "docs/configuration.md", "docs/module-status.md", "docs/feature-status.md", "docs/workspace-status.md", "docs/reference-inventory.md", "docs/reference-redaction-log.md", "docs/repository-completeness.md", "scripts/dev/windows/check-workspace.ps1", "backend/package-lock.json", "scripts/dev/windows/check-backend.ps1", "scripts/dev/windows/check-reference.ps1", "scripts/dev/windows/check-repo-completeness.ps1", "scripts/dev/windows/check-secrets.ps1", "scripts/dev/windows/check-large-files.ps1", "scripts/dev/windows/check-line-endings.ps1", "scripts/dev/windows/check-release-manifest.ps1", "scripts/dev/windows/check-readme-config.ps1", "scripts/dev/windows/check-status-docs.ps1", "scripts/dev/wsl/check-env.sh", "scripts/dev/wsl/check-emqx.sh", "scripts/dev/wsl/start-emqx.sh", "scripts/dev/wsl/stop-emqx.sh", "scripts/dev/wsl/check-workspace.sh", "scripts/dev/wsl/prepare-test-copy.sh", "scripts/dev/wsl/verify-linux.sh", "scripts/dev/wsl/mqtt-smoke.sh", "scripts/dev/wsl/check-gitea-ssh.sh", "scripts/dev/wsl/check-api-domain.sh", "scripts/dev/wsl/cleanup-test-copy.sh" ) $forbiddenTrackedPatterns = @( '(^|/)\.env$', '(^|/)\.env\.(?!example$)', '\.(pem|key|p12|crt|csr)$', '(^|/)node_modules/', '(^|/)dist/', '(^|/)build/', '(^|/)coverage/', '(^|/)\.cache/', '(^|/)\.vite/', '(^|/)logs/', '\.log$', '(^|/)uploads/', '(^|/)backup/', '(^|/)backups/', '\.bak$', '\.dump$', '\.sql\.gz$', '^scripts/dev/wsl/mqtt-smoke\.env$' ) $allowedTrackedRegex = @( '^deploy/backup/' ) function Convert-ToRepoPath { param([string]$Path) return ($Path -replace '\\', '/').TrimStart('./') } function Assert-GitTracked { param([string]$Path) & git -c core.quotePath=false ls-files --error-unmatch -- $Path *> $null if ($LASTEXITCODE -ne 0) { throw "Required repository file is missing or untracked: $Path" } } $origin = & git remote get-url origin if ($origin -ne $expectedOrigin) { throw "Invalid origin: $origin" } $branch = & git branch --show-current if ($branch -ne "main") { throw "Branch must be main, actual: $branch" } $aheadBehind = (& git rev-list --left-right --count main...origin/main).Trim() $aheadBehindParts = $aheadBehind -split '\s+' $ahead = [int]$aheadBehindParts[0] $behind = [int]$aheadBehindParts[1] if ($behind -gt 0) { throw "Local main is behind origin/main or diverged: $aheadBehind" } if ($ahead -gt 0) { Write-Host "INFO: local main is ahead of origin/main; push and verify remote after commit." } else { Write-Host "PASS: local main matches origin/main." } foreach ($path in $requiredPaths) { if (-not (Test-Path $path)) { throw "Required path does not exist: $path" } Assert-GitTracked $path } $untracked = @(& git -c core.quotePath=false status --porcelain=v1 --untracked-files=all | Where-Object { $_.StartsWith("?? ") }) if ($untracked.Count -gt 0) { $untracked | ForEach-Object { Write-Host "UNTRACKED: $_" } throw "Untracked files found. Track deliverables or add an explicit ignore rule." } $nestedGitDirs = @(Get-ChildItem -Force -Directory -Recurse -Filter ".git" -ErrorAction SilentlyContinue | Where-Object { $_.FullName -ne (Join-Path (Get-Location).Path ".git") }) if ($nestedGitDirs.Count -gt 0) { $nestedGitDirs | ForEach-Object { Write-Host "NESTED-GIT: $($_.FullName)" } throw "Nested Git directories found." } $gitModules = @(& git -c core.quotePath=false ls-files -- ".gitmodules") if ($gitModules.Count -gt 0) { $gitModules | ForEach-Object { Write-Host "SUBMODULE-METADATA: $_" } throw "Submodule metadata is tracked; V5.0 requires a single repository." } $tracked = @(& git -c core.quotePath=false ls-files) $forbiddenTracked = @() foreach ($file in $tracked) { $repoPath = Convert-ToRepoPath $file $isAllowed = $false foreach ($allowed in $allowedTrackedRegex) { if ($repoPath -match $allowed) { $isAllowed = $true break } } if ($isAllowed) { continue } foreach ($pattern in $forbiddenTrackedPatterns) { if ($repoPath -match $pattern) { $forbiddenTracked += $repoPath break } } } if ($forbiddenTracked.Count -gt 0) { $forbiddenTracked | Sort-Object -Unique | ForEach-Object { Write-Host "FORBIDDEN-TRACKED: $_" } throw "Forbidden runtime, secret, dependency, build, backup, log, or upload files are tracked." } & git diff --check & powershell -ExecutionPolicy Bypass -File scripts/dev/windows/check-secrets.ps1 & powershell -ExecutionPolicy Bypass -File scripts/dev/windows/check-line-endings.ps1 $ignored = @(& git -c core.quotePath=false status --ignored --short --untracked-files=all | Where-Object { $_ -like "!! *" }) if ($ignored.Count -gt 0) { Write-Host ("INFO: ignored local-only files present: {0}" -f $ignored.Count) } Write-Host "PASS: repository completeness check passed."