Skip to content

Commit b7c62d9

Browse files
authored
Merge branch 'DataDog:main' into patch-1
2 parents b9a9958 + c627814 commit b7c62d9

872 files changed

Lines changed: 47795 additions & 5928 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""PostToolUse / PostToolUseFailure hook: detect missing native extension and suggest rebuild.
2+
3+
When any Bash tool output contains:
4+
ModuleNotFoundError: No module named 'ddtrace.internal.native._native'
5+
6+
it means the C/Rust extensions haven't been compiled. Surfaces the fix
7+
immediately so the agent doesn't waste turns diagnosing it.
8+
"""
9+
10+
import json
11+
import sys
12+
13+
14+
TRIGGER = "No module named 'ddtrace.internal.native._native'"
15+
16+
FIX = """
17+
\u26a0\ufe0f ddtrace native extensions not built (C/Rust extensions missing).
18+
19+
The fix depends on how you are running ddtrace:
20+
21+
Direct Python / pip install
22+
---------------------------
23+
Recompile the extensions in-place:
24+
25+
pip install -e .
26+
27+
Riot (test runner)
28+
------------------
29+
If you are using the -s flag (skip base install), that is why extensions are
30+
missing. Drop -s on your next run so riot rebuilds them:
31+
32+
riot -v run -p <python_version> <suite_name>
33+
34+
Docker / scripts/ddtest
35+
-----------------------
36+
Clean build artifacts on the host first, then remount:
37+
38+
scripts/clean
39+
40+
See docs/troubleshooting.rst for full details.
41+
"""
42+
43+
44+
def _extract_output(tool_response) -> str:
45+
"""Return all text from a tool_response regardless of field shape."""
46+
if isinstance(tool_response, str):
47+
return tool_response
48+
if not isinstance(tool_response, dict):
49+
return ""
50+
parts = []
51+
for key in ("output", "content", "stdout", "stderr"):
52+
val = tool_response.get(key)
53+
if isinstance(val, str) and val:
54+
parts.append(val)
55+
elif isinstance(val, list):
56+
for block in val:
57+
if isinstance(block, dict):
58+
parts.append(block.get("text", ""))
59+
return "\n".join(parts)
60+
61+
62+
def main() -> None:
63+
try:
64+
data = json.load(sys.stdin)
65+
except Exception:
66+
return
67+
68+
if data.get("tool_name") != "Bash":
69+
return
70+
71+
output = _extract_output(data.get("tool_response") or {})
72+
73+
if TRIGGER in output:
74+
print(
75+
json.dumps(
76+
{
77+
"hookSpecificOutput": {
78+
"hookEventName": "PostToolUse",
79+
"suppressOutput": False,
80+
"additionalContext": FIX,
81+
}
82+
}
83+
)
84+
)
85+
86+
87+
if __name__ == "__main__":
88+
main()

.claude/settings.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,29 @@
4040
"Skill(review-ci)"
4141
],
4242
"deny": []
43+
},
44+
"hooks": {
45+
"PostToolUse": [
46+
{
47+
"matcher": "Bash",
48+
"hooks": [
49+
{
50+
"type": "command",
51+
"command": "python3 .claude/hooks/detect-native-build-error.py"
52+
}
53+
]
54+
}
55+
],
56+
"PostToolUseFailure": [
57+
{
58+
"matcher": "Bash",
59+
"hooks": [
60+
{
61+
"type": "command",
62+
"command": "python3 .claude/hooks/detect-native-build-error.py"
63+
}
64+
]
65+
}
66+
]
4367
}
4468
}

0 commit comments

Comments
 (0)