feat(session-handoff): add PostToolUse commit-detector hook [v0.3.0]
Hooks live in skills/session-handoff/hooks/:
- commit-detector.ps1 Windows/PowerShell
- commit-detector.sh POSIX (python3 for JSON parsing)
- README.md opt-in instructions, cross-platform settings.json
snippets, smoke procedure
Hook reads PostToolUse stdin, detects substantive `git commit` (prefix
not in meta/docs/style/chore + fix typo, AND body >200 chars OR files >3).
On hit, emits hookSpecificOutput.additionalContext so Claude Code
surfaces a system reminder next iteration. Silent skip on --amend, failed
commits, non-git cwd, trivial prefix, below thresholds.
install.sh deliberately does NOT mutate settings.json — opt-in via the
README hook config snippet, applied once per machine. SKILL.md body
mentions the hook as an optional alternative to the agent-side
behavioral heuristic.
Bump 0.2.1 -> 0.3.0 MINOR (new opt-in capability, backward-compatible —
SKILL keeps working without the hook).
Deferred (separate follow-ups if needed):
- live-hook e2e smoke (would interfere with current session commits)
- rebase/cherry-pick batch deduplication
Closes [session-handoff-posttooluse-hook] (partial: stdin smoke,
live-hook deferred).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
69
skills/session-handoff/hooks/commit-detector.ps1
Normal file
69
skills/session-handoff/hooks/commit-detector.ps1
Normal file
@@ -0,0 +1,69 @@
|
||||
#!/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()
|
||||
$body = (& git -C $cwd log -1 --format='%b')
|
||||
$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
|
||||
$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
|
||||
Reference in New Issue
Block a user