106 lines
3.4 KiB
PowerShell
106 lines
3.4 KiB
PowerShell
# Changelog sync guard — 统一 stop hook
|
||
#
|
||
# 用确定性逻辑检查:
|
||
# 1. 源文件是否比 changelog 更新(mtime 比较)
|
||
# 2. stdin 中的 agent 上下文是否显示有源文件编辑操作
|
||
#
|
||
# 静默条件(不触发提醒):
|
||
# 1. 环境变量 CURSOR_SKIP_CHANGELOG 被设置(sessionStart 在非 agent 模式设置)
|
||
# 2. stdin JSON 中 composer_mode 不是 "agent"(如 debug/ask/edit 模式)
|
||
# 3. changelog 文件不存在
|
||
# 4. .changelog-ack 标记文件存在且足够新(本会话已确认过 changelog 状态)
|
||
# 5. 没有源文件比 changelog 更新
|
||
# 6. stdin 上下文中没有文件编辑操作的证据(防止跨会话残留 mtime 误触发)
|
||
|
||
$input = [Console]::In.ReadToEnd()
|
||
|
||
# === 豁免检查 1:环境变量跳过标志 ===
|
||
if ($env:CURSOR_SKIP_CHANGELOG) {
|
||
Write-Output '{}'
|
||
exit 0
|
||
}
|
||
|
||
# === 豁免检查 2:从 stdin 解析 composer_mode ===
|
||
try {
|
||
$data = $input | ConvertFrom-Json
|
||
$mode = $data.composer_mode
|
||
if ($mode -and $mode -ne "agent") {
|
||
Write-Output '{}'
|
||
exit 0
|
||
}
|
||
} catch {
|
||
# JSON 解析失败,继续后续检查
|
||
}
|
||
|
||
# === 豁免检查 3:从 stdin 文本匹配 debug 上下文关键词 ===
|
||
# stop hook 的 $ARGUMENTS 可能包含对话/工具上下文,检测 debug 相关信号
|
||
if ($input -match '"mode"\s*:\s*"debug"' -or
|
||
$input -match 'debug[\s_-]?mode' -or
|
||
$input -match 'Debug Mode') {
|
||
Write-Output '{}'
|
||
exit 0
|
||
}
|
||
|
||
$changelog = ".cursor\changelog\changelog-headlines.md"
|
||
$srcDir = "art-agent"
|
||
|
||
# === 豁免检查 4:changelog 文件不存在 ===
|
||
if (-not (Test-Path $changelog)) {
|
||
Write-Output '{}'
|
||
exit 0
|
||
}
|
||
|
||
$clMtime = (Get-Item $changelog).LastWriteTime
|
||
|
||
# === 豁免检查 5:ack 标记文件足够新 ===
|
||
$ackFile = ".cursor\changelog\.changelog-ack"
|
||
if ((Test-Path $ackFile) -and (Get-Item $ackFile).LastWriteTime -ge $clMtime) {
|
||
Write-Output '{}'
|
||
exit 0
|
||
}
|
||
|
||
# === 豁免检查 6:stdin 中无文件编辑证据 ===
|
||
# 防止跨会话残留 mtime 差异导致误触发:如果 ack 文件不存在(或过旧),
|
||
# 但 stdin 上下文中也没有任何文件写入/编辑操作的痕迹,说明本次会话
|
||
# 没有进行代码改动,不应触发提醒。
|
||
$hasEditEvidence = (
|
||
$input -match 'StrReplace|Write\s*tool|edit_file|file_write|write_to_file' -or
|
||
$input -match 'Created file|Modified file|Wrote contents' -or
|
||
$input -match '"tool"\s*:\s*"(str_replace|write|edit)"'
|
||
)
|
||
if (-not $hasEditEvidence) {
|
||
Write-Output '{}'
|
||
exit 0
|
||
}
|
||
|
||
# === 核心检查:是否有源文件比 changelog 更新 ===
|
||
$extensions = @("*.py", "*.tsx", "*.ts", "*.css")
|
||
$excludeDirs = @("node_modules", ".next", "__pycache__", "venv")
|
||
|
||
$newerFile = $null
|
||
foreach ($ext in $extensions) {
|
||
$files = Get-ChildItem -Path $srcDir -Filter $ext -Recurse -ErrorAction SilentlyContinue |
|
||
Where-Object {
|
||
$skip = $false
|
||
foreach ($ex in $excludeDirs) {
|
||
if ($_.FullName -like "*\$ex\*") { $skip = $true; break }
|
||
}
|
||
-not $skip -and $_.LastWriteTime -gt $clMtime
|
||
} |
|
||
Select-Object -First 1
|
||
|
||
if ($files) {
|
||
$newerFile = $files.Name
|
||
break
|
||
}
|
||
}
|
||
|
||
if ($newerFile) {
|
||
$msg = "[Hook] Source file updated (e.g. $newerFile) but changelog not synced. Run dev-changelog Skill operation A NOW to write all three changelog layers."
|
||
$json = '{"followup_message":"' + $msg.Replace('"','\"') + '"}'
|
||
Write-Output $json
|
||
} else {
|
||
Write-Output '{}'
|
||
}
|
||
exit 0
|