1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
# installed by herdr
# managed by herdr; reinstalling or updating the integration overwrites this file.
# add custom hooks beside this file instead of editing it.
# HERDR_INTEGRATION_ID=copilot
# HERDR_INTEGRATION_VERSION=1
if ($env:HERDR_ENV -ne "1") { exit 0 }
if ([string]::IsNullOrWhiteSpace($env:HERDR_PANE_ID)) { exit 0 }
$inputText = [Console]::In.ReadToEnd()
try {
$payload = if ([string]::IsNullOrWhiteSpace($inputText)) { @{} } else { $inputText | ConvertFrom-Json }
} catch {
$payload = @{}
}
function First-Text {
param([object[]]$Names)
foreach ($name in $Names) {
$value = $payload.$name
if ($value -is [string] -and -not [string]::IsNullOrWhiteSpace($value)) {
return $value
}
}
return $null
}
function Normalize-Event {
param([string]$Event)
if ([string]::IsNullOrWhiteSpace($Event)) { return "" }
return $Event.Replace("_", "").Replace("-", "").ToLowerInvariant()
}
function Infer-Event {
$explicit = First-Text @("hook_event_name", "hookEventName")
if ($explicit) { return $explicit }
if (First-Text @("notification_type", "notificationType")) { return "notification" }
if ($payload.PSObject.Properties.Name -contains "toolResult" -or $payload.PSObject.Properties.Name -contains "tool_result") { return "postToolUse" }
if (($payload.PSObject.Properties.Name -contains "error") -and (First-Text @("tool_name", "toolName"))) { return "postToolUseFailure" }
if (First-Text @("tool_name", "toolName")) { return "preToolUse" }
if (First-Text @("stop_reason", "stopReason")) { return "agentStop" }
if (First-Text @("reason")) { return "sessionEnd" }
if ($payload.PSObject.Properties.Name -contains "prompt") { return "userPromptSubmitted" }
if (
$payload.PSObject.Properties.Name -contains "initial_prompt" -or
$payload.PSObject.Properties.Name -contains "initialPrompt" -or
$payload.PSObject.Properties.Name -contains "source" -or
(First-Text @("session_id", "sessionId"))
) { return "sessionStart" }
return ""
}
function Has-Initial-Prompt {
$value = $payload.initial_prompt
if ($null -eq $value) { $value = $payload.initialPrompt }
return ($value -is [string] -and -not [string]::IsNullOrWhiteSpace($value))
}
function Report-State {
param([string]$State, [string]$SessionId)
$seq = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
$args = @("pane", "report-agent", $env:HERDR_PANE_ID, "--source", "herdr:copilot", "--agent", "copilot", "--state", $State, "--seq", "$seq")
if (-not [string]::IsNullOrWhiteSpace($SessionId)) {
$args += @("--agent-session-id", $SessionId)
}
& herdr @args 2>$null | Out-Null
}
function Release-Agent {
$seq = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
& herdr pane release-agent $env:HERDR_PANE_ID --source herdr:copilot --agent copilot --seq $seq 2>$null | Out-Null
}
try {
$eventKey = Normalize-Event (Infer-Event)
$sessionId = First-Text @("session_id", "sessionId")
$toolName = First-Text @("tool_name", "toolName")
$notificationType = First-Text @("notification_type", "notificationType")
$stopReason = First-Text @("stop_reason", "stopReason")
$reason = First-Text @("reason")
if ($eventKey -eq "sessionstart") {
Report-State ($(if (Has-Initial-Prompt) { "working" } else { "idle" })) $sessionId
} elseif ($eventKey -in @("userpromptsubmit", "userpromptsubmitted")) {
Report-State "working" $sessionId
} elseif ($eventKey -eq "pretooluse") {
Report-State ($(if ($toolName -in @("ask_user", "exit_plan_mode")) { "blocked" } else { "working" })) $sessionId
} elseif ($eventKey -in @("posttooluse", "posttoolusefailure")) {
if ($toolName -ne "report_intent") { Report-State "working" $sessionId }
} elseif ($eventKey -eq "notification") {
if ($notificationType -in @("permission_prompt", "elicitation_dialog")) {
Report-State "blocked" $sessionId
} elseif ($notificationType -eq "agent_idle") {
Report-State "idle" $sessionId
}
} elseif ($eventKey -in @("stop", "agentstop", "sessionstop")) {
if ([string]::IsNullOrWhiteSpace($stopReason) -or $stopReason -eq "end_turn") {
Report-State "idle" $sessionId
}
} elseif ($eventKey -eq "sessionend") {
if ($reason -in @("user_exit", "abort")) { Release-Agent }
}
} catch {
}
|