init: 项目初始提交 - NeoZQYY Monorepo 完整代码

This commit is contained in:
Neo
2026-02-15 14:58:14 +08:00
commit ded6dfb9d8
769 changed files with 182616 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
# audit_flagger.ps1 — 判断 git 工作区是否存在高风险改动
# 兼容 Windows PowerShell 5.1(避免 try{} 内嵌套脚本块的解析器 bug
$ErrorActionPreference = "SilentlyContinue"
function Get-TaipeiNow {
$tz = [TimeZoneInfo]::FindSystemTimeZoneById("Taipei Standard Time")
if ($tz) {
return [TimeZoneInfo]::ConvertTime([DateTimeOffset]::Now, $tz)
}
return [DateTimeOffset]::Now
}
function Sha1Hex([string]$s) {
$sha1 = [System.Security.Cryptography.SHA1]::Create()
$bytes = [System.Text.Encoding]::UTF8.GetBytes($s)
$hash = $sha1.ComputeHash($bytes)
return ([BitConverter]::ToString($hash) -replace "-", "").ToLowerInvariant()
}
function Get-ChangedFiles {
$status = git status --porcelain 2>$null
if ($LASTEXITCODE -ne 0) { return @() }
$result = @()
foreach ($line in $status) {
if ([string]::IsNullOrWhiteSpace($line)) { continue }
$pathPart = $line.Substring([Math]::Min(3, $line.Length - 1)).Trim()
if ($pathPart -match " -> ") { $pathPart = ($pathPart -split " -> ")[-1] }
if ([string]::IsNullOrWhiteSpace($pathPart)) { continue }
$result += $pathPart.Replace("\", "/").Trim()
}
return $result
}
function Test-NoiseFile([string]$f) {
if ($f -match "^docs/audit/") { return $true }
if ($f -match "^\.kiro/\.audit_state\.json$") { return $true }
if ($f -match "^\.kiro/\.last_prompt_id\.json$") { return $true }
if ($f -match "^\.kiro/scripts/") { return $true }
return $false
}
function Write-AuditState([string]$json) {
$null = New-Item -ItemType Directory -Force -Path ".kiro" 2>$null
Set-Content -Path ".kiro/.audit_state.json" -Value $json -Encoding UTF8
}
# --- 主逻辑 ---
# 非 git 仓库直接退出
$null = git rev-parse --is-inside-work-tree 2>$null
if ($LASTEXITCODE -ne 0) { exit 0 }
$allFiles = Get-ChangedFiles
# 过滤噪声
$files = @()
foreach ($f in $allFiles) {
if (-not (Test-NoiseFile $f)) { $files += $f }
}
$files = $files | Sort-Object -Unique
$now = Get-TaipeiNow
if ($files.Count -eq 0) {
$json = '{"audit_required":false,"db_docs_required":false,"reasons":[],"changed_files":[],"change_fingerprint":"","marked_at":"' + $now.ToString("o") + '","last_reminded_at":null}'
Write-AuditState $json
exit 0
}
# 高风险路径("regex|label" 格式,避免 @{} 哈希表在 PS 5.1 的解析问题)
$riskRules = @(
"^apps/etl/pipelines/feiqiu/(api|cli|config|database|loaders|models|orchestration|scd|tasks|utils|quality)/|etl",
"^apps/backend/app/|backend",
"^packages/shared/|shared",
"^db/|db"
)
$reasons = @()
$auditRequired = $false
$dbDocsRequired = $false
foreach ($f in $files) {
foreach ($rule in $riskRules) {
$idx = $rule.LastIndexOf("|")
$pat = $rule.Substring(0, $idx)
$lbl = $rule.Substring($idx + 1)
if ($f -match $pat) {
$auditRequired = $true
$tag = "dir:" + $lbl
if ($reasons -notcontains $tag) { $reasons += $tag }
}
}
if ($f -notmatch "/") {
$auditRequired = $true
if ($reasons -notcontains "root-file") { $reasons += "root-file" }
}
if ($f -match "^db/" -or $f -match "/migrations/" -or $f -match "\.sql$" -or $f -match "\.prisma$") {
$dbDocsRequired = $true
if ($reasons -notcontains "db-schema-change") { $reasons += "db-schema-change" }
}
}
$fp = Sha1Hex(($files -join "`n"))
# 读取已有状态以保留 last_reminded_at
$lastReminded = $null
if (Test-Path ".kiro/.audit_state.json") {
$raw = Get-Content ".kiro/.audit_state.json" -Raw 2>$null
if ($raw) {
$existing = $raw | ConvertFrom-Json 2>$null
if ($existing -and $existing.change_fingerprint -eq $fp) {
$lastReminded = $existing.last_reminded_at
}
}
}
$stateObj = [ordered]@{
audit_required = [bool]$auditRequired
db_docs_required = [bool]$dbDocsRequired
reasons = $reasons
changed_files = $files | Select-Object -First 50
change_fingerprint = $fp
marked_at = $now.ToString("o")
last_reminded_at = $lastReminded
}
Write-AuditState ($stateObj | ConvertTo-Json -Depth 6)
exit 0

View File

@@ -0,0 +1,72 @@
$ErrorActionPreference = "Stop"
function Get-TaipeiNow {
try {
$tz = [TimeZoneInfo]::FindSystemTimeZoneById("Taipei Standard Time")
return [TimeZoneInfo]::ConvertTime([DateTimeOffset]::Now, $tz)
} catch {
return [DateTimeOffset]::Now
}
}
try {
$statePath = ".kiro/.audit_state.json"
if (-not (Test-Path $statePath)) { exit 0 }
$state = $null
try { $state = Get-Content $statePath -Raw | ConvertFrom-Json } catch { exit 0 }
if (-not $state) { exit 0 }
# If no pending audit, do nothing
if (-not $state.audit_required) { exit 0 }
# If working tree is clean (ignoring logs/state), stop reminding
$null = git rev-parse --is-inside-work-tree 2>$null
if ($LASTEXITCODE -ne 0) { exit 0 }
$status = git status --porcelain
$files = @()
foreach ($line in $status) {
if ([string]::IsNullOrWhiteSpace($line)) { continue }
$pathPart = $line.Substring([Math]::Min(3, $line.Length-1)).Trim()
if ($pathPart -match " -> ") { $pathPart = ($pathPart -split " -> ")[-1] }
$p = $pathPart.Replace("\", "/").Trim()
if ($p -and $p -notmatch "^docs/audit/" -and $p -notmatch "^\.kiro/") { $files += $p }
}
if (($files | Sort-Object -Unique).Count -eq 0) {
$state.audit_required = $false
$state.reasons = @()
$state.changed_files = @()
$state.last_reminded_at = $null
($state | ConvertTo-Json -Depth 6) | Set-Content -Path $statePath -Encoding UTF8
exit 0
}
$now = Get-TaipeiNow
$minInterval = [TimeSpan]::FromMinutes(15)
$last = $null
if ($state.last_reminded_at) {
try { $last = [DateTimeOffset]::Parse($state.last_reminded_at) } catch { $last = $null }
}
$shouldRemind = $true
if ($last) {
$elapsed = $now - $last
if ($elapsed -lt $minInterval) { $shouldRemind = $false }
}
if (-not $shouldRemind) { exit 0 }
# Update last_reminded_at (persist even if user ignores)
$state.last_reminded_at = $now.ToString("o")
($state | ConvertTo-Json -Depth 6) | Set-Content -Path $statePath -Encoding UTF8
$reasons = @()
if ($state.reasons) { $reasons = @($state.reasons) }
$reasonText = if ($reasons.Count -gt 0) { ($reasons -join ", ") } else { "high-risk paths changed" }
[Console]::Error.WriteLine("[AUDIT REMINDER] Pending audit detected ($reasonText). Run /audit (Manual: Run /audit hook) to sync docs & write audit artifacts. (rate limit: 15min)")
exit 1
} catch {
exit 0
}

View File

@@ -0,0 +1,61 @@
$ErrorActionPreference = "Stop"
function Get-TaipeiNow {
try {
$tz = [TimeZoneInfo]::FindSystemTimeZoneById("Taipei Standard Time")
return [TimeZoneInfo]::ConvertTime([DateTimeOffset]::Now, $tz)
} catch {
return [DateTimeOffset]::Now
}
}
try {
$now = Get-TaipeiNow
$promptId = "P{0}" -f $now.ToString("yyyyMMdd-HHmmss")
$promptRaw = $env:USER_PROMPT
if ($null -eq $promptRaw) { $promptRaw = "" }
# 截断过长的 prompt避免意外记录展开的 #context
if ($promptRaw.Length -gt 20000) {
$promptRaw = $promptRaw.Substring(0, 5000) + "`n[TRUNCATED: prompt too long; possible expanded #context]"
}
$summary = ($promptRaw -replace "\s+", " ").Trim()
if ($summary.Length -gt 120) { $summary = $summary.Substring(0, 120) + "" }
if ([string]::IsNullOrWhiteSpace($summary)) { $summary = "(empty prompt)" }
# CHANGE [2026-02-15] intent: 简化为每次直接写独立文件到 prompt_logs/,不再维护 prompt_log.md 中间文件
$logDir = Join-Path "docs" "audit" "prompt_logs"
$null = New-Item -ItemType Directory -Force -Path $logDir 2>$null
$filename = "prompt_log_{0}.md" -f $now.ToString("yyyyMMdd_HHmmss")
$targetLog = Join-Path $logDir $filename
$timestamp = $now.ToString("yyyy-MM-dd HH:mm:ss zzz")
$entry = @"
- [$promptId] $timestamp
- summary: $summary
- prompt:
``````text
$promptRaw
``````
"@
Set-Content -Path $targetLog -Value $entry -Encoding UTF8
# 保存 last prompt id 供下游 /audit 溯源
$stateDir = ".kiro"
$null = New-Item -ItemType Directory -Force -Path $stateDir 2>$null
$lastPrompt = @{
prompt_id = $promptId
at = $now.ToString("o")
} | ConvertTo-Json -Depth 4
Set-Content -Path (Join-Path $stateDir ".last_prompt_id.json") -Value $lastPrompt -Encoding UTF8
exit 0
} catch {
# 不阻塞 prompt 提交
exit 0
}