11import hashlib
22import json
33import re
4+ from datetime import datetime , timezone
45from typing import Any , Dict , List , Sequence , Set
56
67from notifypy import Notify
@@ -75,6 +76,8 @@ def parse_hook_input(raw_content: str) -> list[HookPayload]:
7576 but in some cases files mentioned in the prompt will be read but the
7677 PreToolUse event will not be called. So we need to handle this case ourselves.
7778 """
79+ timestamp = datetime .now (timezone .utc )
80+
7881 # Parse the content as JSON
7982 if not raw_content .strip ():
8083 raise ValueError ("Error: No input received on stdin" )
@@ -103,7 +106,7 @@ def parse_hook_input(raw_content: str) -> list[HookPayload]:
103106 content = data .get ("prompt" , "" )
104107 # Look for files mentioned in the prompt that could be read
105108 # without triggering a PRE_TOOL_USE event.
106- payloads .extend (_parse_user_prompt (content , event_type , agent ))
109+ payloads .extend (_parse_user_prompt (content , event_type , agent , timestamp ))
107110
108111 elif event_type == EventType .PRE_TOOL_USE :
109112 tool = _parse_tool (data )
@@ -115,7 +118,7 @@ def parse_hook_input(raw_content: str) -> list[HookPayload]:
115118 content = tool_input .get ("command" , "" )
116119 identifier = content
117120 # Try to detect a command that could be used to read a file.
118- payloads .extend (_parse_command (content , event_type , agent ))
121+ payloads .extend (_parse_command (content , event_type , agent , timestamp ))
119122 elif tool == Tool .READ :
120123 # We only need to deal with the identifier, the content will be read by the Scannable
121124 identifier = lookup (tool_input , ["file_path" , "filePath" , "path" ], "" )
@@ -139,6 +142,7 @@ def parse_hook_input(raw_content: str) -> list[HookPayload]:
139142 identifier = identifier ,
140143 agent = agent ,
141144 raw = data ,
145+ timestamp = timestamp ,
142146 )
143147 )
144148
@@ -166,7 +170,7 @@ def _detect_agent(data: Dict[str, Any]) -> Agent:
166170
167171
168172def _parse_user_prompt (
169- content : str , event_type : EventType , agent : Agent
173+ content : str , event_type : EventType , agent : Agent , timestamp : datetime
170174) -> List [HookPayload ]:
171175 """Parse the user prompt for additional payloads that we may miss."""
172176 payloads = []
@@ -183,13 +187,14 @@ def _parse_user_prompt(
183187 identifier = match ,
184188 agent = agent ,
185189 raw = {},
190+ timestamp = timestamp ,
186191 )
187192 )
188193 return payloads
189194
190195
191196def _parse_command (
192- content : str , event_type : EventType , agent : Agent
197+ content : str , event_type : EventType , agent : Agent , timestamp : datetime
193198) -> List [HookPayload ]:
194199 """Parse the command for additional payloads that we may miss."""
195200 # In Windows, some agents (at least Codex) use the Get-Content command to read a file.
@@ -207,6 +212,7 @@ def _parse_command(
207212 identifier = identifier ,
208213 agent = agent ,
209214 raw = {},
215+ timestamp = timestamp ,
210216 )
211217 )
212218 return payloads
0 commit comments