`(& git log -1 --format='%b')` in PowerShell collapses multi-line subprocess
output into string[]. The threshold check used `$body.Length` which on a
string[] returns the line count, not char count — so the body>200 condition
was effectively comparing "more than 200 lines", which is much harder to
meet. Files-count saves it in practice for big commits, but small-file
big-message commits were under-detected.
Fix: join the array back into a single string with `-join "`n"` before
measuring length. Verified via stdin-pipe smoke against current HEAD:
body chars now report 1255 (vs 29 before — the line count).
POSIX `.sh` variant unaffected — `$()` collapses output and `${#var}` is
char count.
Bump 0.3.0 → 0.3.1 PATCH (bugfix, no behavior contract change).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
2.8 KiB
PowerShell
73 lines
2.8 KiB
PowerShell
#!/usr/bin/env pwsh
|
|
# session-handoff PostToolUse hook (PowerShell).
|
|
#
|
|
# Reads PostToolUse JSON from stdin, detects whether the just-completed
|
|
# Bash tool call was a substantive `git commit`, and on hit emits JSON to
|
|
# stdout with `additionalContext` so Claude Code surfaces a system reminder
|
|
# in the next agent iteration ("substantive commit — consider session-handoff
|
|
# write-mode").
|
|
#
|
|
# Substantive heuristic (mirrors session-handoff SKILL.md):
|
|
# prefix NOT in (meta:|docs:|style:|chore:|fix typo) AND
|
|
# (body > 200 chars OR files > 3)
|
|
#
|
|
# Silent skip on: malformed JSON, no command, --amend, failed commit,
|
|
# non-git cwd, trivial prefix, below thresholds. Never blocks the tool call
|
|
# (PostToolUse cannot, by design).
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# Read stdin
|
|
try {
|
|
$raw = [Console]::In.ReadToEnd()
|
|
if ([string]::IsNullOrWhiteSpace($raw)) { exit 0 }
|
|
$hook = $raw | ConvertFrom-Json -ErrorAction Stop
|
|
} catch {
|
|
exit 0
|
|
}
|
|
|
|
# Only Bash tool, only git commit (not --amend)
|
|
$cmd = $hook.tool_input.command
|
|
if (-not $cmd) { exit 0 }
|
|
if ($cmd -notmatch '(?<![\w-])git\s+commit(?![\w-])') { exit 0 }
|
|
if ($cmd -match '(?<![\w-])git\s+commit\b.*--amend') { exit 0 }
|
|
|
|
# Only on successful commit
|
|
if ($null -ne $hook.tool_response.exit_code -and $hook.tool_response.exit_code -ne 0) { exit 0 }
|
|
|
|
# Resolve cwd; require a git work-tree
|
|
$cwd = $hook.cwd
|
|
if (-not $cwd) { $cwd = (Get-Location).Path }
|
|
$inside = & git -C $cwd rev-parse --is-inside-work-tree 2>$null
|
|
if ($inside -ne 'true') { exit 0 }
|
|
|
|
# Parse last commit
|
|
$subject = (& git -C $cwd log -1 --format='%s').Trim()
|
|
# PowerShell collapses multi-line subprocess output into string[] — join back so
|
|
# .Length below is char count, not line count.
|
|
$body = ((& git -C $cwd log -1 --format='%b') -join "`n")
|
|
$files = ((& git -C $cwd diff-tree --no-commit-id --name-only -r HEAD) | Measure-Object).Count
|
|
|
|
# Trivial-prefix check (Conventional Commits prefix before optional scope + colon)
|
|
$prefix = $subject -replace '^([a-z]+)(\([^)]+\))?:.*$','$1'
|
|
$trivial = @('meta','docs','style','chore')
|
|
if ($trivial -contains $prefix) { exit 0 }
|
|
if ($subject -match 'fix\s+typo') { exit 0 }
|
|
|
|
# Threshold check (chars for body, count for files)
|
|
$bodyLen = if ($body) { $body.Length } else { 0 }
|
|
if ($bodyLen -le 200 -and $files -le 3) { exit 0 }
|
|
|
|
|
|
# Substantive — emit JSON
|
|
$msg = "Substantive commit detected on " + $cwd + ": ``" + $subject + "`` (" + $files + " files changed, body " + $bodyLen + " chars). Consider invoking session-handoff write-mode to update .tasks/NEXT_SESSION.md."
|
|
|
|
@{
|
|
hookSpecificOutput = @{
|
|
hookEventName = 'PostToolUse'
|
|
additionalContext = $msg
|
|
}
|
|
systemMessage = 'session-handoff: substantive commit detected'
|
|
suppressOutput = $false
|
|
} | ConvertTo-Json -Compress -Depth 5 | Write-Output
|