claude-mpm 4.1.8__py3-none-any.whl → 4.1.11__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/INSTRUCTIONS.md +26 -1
  3. claude_mpm/agents/agents_metadata.py +57 -0
  4. claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
  5. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
  6. claude_mpm/agents/templates/agent-manager.json +263 -17
  7. claude_mpm/agents/templates/agentic_coder_optimizer.json +222 -0
  8. claude_mpm/agents/templates/code_analyzer.json +18 -8
  9. claude_mpm/agents/templates/engineer.json +1 -1
  10. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
  11. claude_mpm/agents/templates/qa.json +1 -1
  12. claude_mpm/agents/templates/research.json +1 -1
  13. claude_mpm/cli/__init__.py +15 -0
  14. claude_mpm/cli/commands/__init__.py +6 -0
  15. claude_mpm/cli/commands/analyze.py +548 -0
  16. claude_mpm/cli/commands/analyze_code.py +524 -0
  17. claude_mpm/cli/commands/configure.py +78 -28
  18. claude_mpm/cli/commands/configure_tui.py +62 -60
  19. claude_mpm/cli/commands/dashboard.py +288 -0
  20. claude_mpm/cli/commands/debug.py +1386 -0
  21. claude_mpm/cli/commands/mpm_init.py +427 -0
  22. claude_mpm/cli/commands/mpm_init_handler.py +83 -0
  23. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  24. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  25. claude_mpm/cli/parsers/base_parser.py +44 -0
  26. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  27. claude_mpm/cli/parsers/debug_parser.py +319 -0
  28. claude_mpm/cli/parsers/mpm_init_parser.py +122 -0
  29. claude_mpm/constants.py +13 -1
  30. claude_mpm/core/framework_loader.py +148 -6
  31. claude_mpm/core/log_manager.py +16 -13
  32. claude_mpm/core/logger.py +1 -1
  33. claude_mpm/core/unified_agent_registry.py +1 -1
  34. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
  35. claude_mpm/dashboard/analysis_runner.py +455 -0
  36. claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
  37. claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
  38. claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
  39. claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
  40. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  41. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
  42. claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
  43. claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
  44. claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
  45. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  46. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  47. claude_mpm/dashboard/static/css/activity.css +549 -0
  48. claude_mpm/dashboard/static/css/code-tree.css +1175 -0
  49. claude_mpm/dashboard/static/css/dashboard.css +245 -0
  50. claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
  51. claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
  52. claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
  53. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  54. claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
  55. claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
  56. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  57. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  58. claude_mpm/dashboard/static/js/components/activity-tree.js +1338 -0
  59. claude_mpm/dashboard/static/js/components/code-tree.js +2535 -0
  60. claude_mpm/dashboard/static/js/components/code-viewer.js +480 -0
  61. claude_mpm/dashboard/static/js/components/event-viewer.js +59 -9
  62. claude_mpm/dashboard/static/js/components/session-manager.js +40 -4
  63. claude_mpm/dashboard/static/js/components/socket-manager.js +12 -0
  64. claude_mpm/dashboard/static/js/components/ui-state-manager.js +4 -0
  65. claude_mpm/dashboard/static/js/components/working-directory.js +17 -1
  66. claude_mpm/dashboard/static/js/dashboard.js +51 -0
  67. claude_mpm/dashboard/static/js/socket-client.js +465 -29
  68. claude_mpm/dashboard/templates/index.html +182 -4
  69. claude_mpm/hooks/claude_hooks/hook_handler.py +182 -5
  70. claude_mpm/hooks/claude_hooks/installer.py +386 -113
  71. claude_mpm/scripts/claude-hook-handler.sh +161 -0
  72. claude_mpm/scripts/socketio_daemon.py +121 -8
  73. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +2 -2
  74. claude_mpm/services/agents/deployment/agent_record_service.py +1 -2
  75. claude_mpm/services/agents/memory/memory_format_service.py +1 -3
  76. claude_mpm/services/cli/agent_cleanup_service.py +1 -5
  77. claude_mpm/services/cli/agent_dependency_service.py +1 -1
  78. claude_mpm/services/cli/agent_validation_service.py +3 -4
  79. claude_mpm/services/cli/dashboard_launcher.py +2 -3
  80. claude_mpm/services/cli/startup_checker.py +0 -11
  81. claude_mpm/services/core/cache_manager.py +1 -3
  82. claude_mpm/services/core/path_resolver.py +1 -4
  83. claude_mpm/services/core/service_container.py +2 -2
  84. claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
  85. claude_mpm/services/infrastructure/monitoring/__init__.py +11 -11
  86. claude_mpm/services/infrastructure/monitoring.py +11 -11
  87. claude_mpm/services/project/architecture_analyzer.py +1 -1
  88. claude_mpm/services/project/dependency_analyzer.py +4 -4
  89. claude_mpm/services/project/language_analyzer.py +3 -3
  90. claude_mpm/services/project/metrics_collector.py +3 -6
  91. claude_mpm/services/socketio/event_normalizer.py +64 -0
  92. claude_mpm/services/socketio/handlers/__init__.py +2 -0
  93. claude_mpm/services/socketio/handlers/code_analysis.py +672 -0
  94. claude_mpm/services/socketio/handlers/registry.py +2 -0
  95. claude_mpm/services/socketio/server/connection_manager.py +6 -4
  96. claude_mpm/services/socketio/server/core.py +100 -11
  97. claude_mpm/services/socketio/server/main.py +8 -2
  98. claude_mpm/services/visualization/__init__.py +19 -0
  99. claude_mpm/services/visualization/mermaid_generator.py +938 -0
  100. claude_mpm/tools/__main__.py +208 -0
  101. claude_mpm/tools/code_tree_analyzer.py +1596 -0
  102. claude_mpm/tools/code_tree_builder.py +631 -0
  103. claude_mpm/tools/code_tree_events.py +416 -0
  104. claude_mpm/tools/socketio_debug.py +671 -0
  105. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/METADATA +2 -1
  106. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/RECORD +110 -74
  107. claude_mpm/agents/schema/agent_schema.json +0 -314
  108. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/WHEEL +0 -0
  109. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/entry_points.txt +0 -0
  110. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/licenses/LICENSE +0 -0
  111. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/top_level.txt +0 -0
@@ -15,6 +15,9 @@
15
15
 
16
16
  <!-- External Dependencies -->
17
17
  <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
18
+
19
+ <!-- D3.js for Activity Tree Visualization -->
20
+ <script src="https://d3js.org/d3.v7.min.js"></script>
18
21
 
19
22
  <!-- Syntax Highlighting - Prism.js -->
20
23
  <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet">
@@ -26,6 +29,8 @@
26
29
  <!-- Stylesheets -->
27
30
  <link rel="stylesheet" href="/static/css/dashboard.css">
28
31
  <link rel="stylesheet" href="/static/css/connection-status.css">
32
+ <link rel="stylesheet" href="/static/css/activity.css">
33
+ <link rel="stylesheet" href="/static/css/code-tree.css">
29
34
 
30
35
  <!-- Additional styles for file operations -->
31
36
  <style>
@@ -236,10 +241,12 @@
236
241
  <div class="events-container">
237
242
  <!-- Tab Navigation -->
238
243
  <div class="tab-nav">
239
- <button class="tab-button active">📊 Events</button>
240
- <button class="tab-button">🤖 Agents</button>
241
- <button class="tab-button">🔧 Tools</button>
242
- <button class="tab-button">📁 Files</button>
244
+ <button class="tab-button active" data-tab="events">📊 Events</button>
245
+ <button class="tab-button" data-tab="agents">🤖 Agents</button>
246
+ <button class="tab-button" data-tab="tools">🔧 Tools</button>
247
+ <button class="tab-button" data-tab="files">📁 Files</button>
248
+ <button class="tab-button" data-tab="activity">🌳 Activity</button>
249
+ <button class="tab-button" data-tab="code">🧬 Code</button>
243
250
  </div>
244
251
 
245
252
  <!-- Events Tab -->
@@ -316,11 +323,167 @@
316
323
  </div>
317
324
  </div>
318
325
  </div>
326
+
327
+ <!-- Activity Tab -->
328
+ <div class="tab-content" id="activity-tab">
329
+ <div class="activity-container">
330
+ <div class="activity-header">
331
+ <div class="activity-controls">
332
+ <button id="expand-all" class="btn-sm">Expand All</button>
333
+ <button id="collapse-all" class="btn-sm">Collapse All</button>
334
+ <button id="reset-zoom" class="btn-sm">Reset Zoom</button>
335
+ <select id="time-range">
336
+ <option value="all">All Time</option>
337
+ <option value="hour">Last Hour</option>
338
+ <option value="30min" selected>Last 30 Minutes</option>
339
+ <option value="10min">Last 10 Minutes</option>
340
+ </select>
341
+ <input type="text" id="activity-search" placeholder="Search nodes...">
342
+ </div>
343
+ <div class="activity-stats">
344
+ <span class="stat-item">
345
+ <span class="stat-label">Nodes:</span>
346
+ <span id="node-count" class="stat-value">0</span>
347
+ </span>
348
+ <span class="stat-item">
349
+ <span class="stat-label">Active:</span>
350
+ <span id="active-count" class="stat-value">0</span>
351
+ </span>
352
+ <span class="stat-item">
353
+ <span class="stat-label">Depth:</span>
354
+ <span id="tree-depth" class="stat-value">0</span>
355
+ </span>
356
+ </div>
357
+ </div>
358
+ <div id="activity-tree-container" class="activity-tree-container">
359
+ <div id="activity-tree"></div>
360
+ <div class="tree-legend">
361
+ <div class="legend-item">
362
+ <span class="legend-icon pm">●</span>
363
+ <span>PM</span>
364
+ </div>
365
+ <div class="legend-item">
366
+ <span class="legend-icon todowrite">■</span>
367
+ <span>TodoWrite</span>
368
+ </div>
369
+ <div class="legend-item">
370
+ <span class="legend-icon agent">●</span>
371
+ <span>Agent</span>
372
+ </div>
373
+ <div class="legend-item">
374
+ <span class="legend-icon tool">●</span>
375
+ <span>Tool</span>
376
+ </div>
377
+ <div class="legend-item">
378
+ <span class="legend-icon file">●</span>
379
+ <span>File/Command</span>
380
+ </div>
381
+ </div>
382
+ </div>
383
+ <div class="activity-breadcrumb" id="activity-breadcrumb">
384
+ PM > Click a node to see path
385
+ </div>
386
+ </div>
387
+ </div>
388
+
389
+ <!-- Code Tab -->
390
+ <div class="tab-content" id="code-tab">
391
+ <div class="code-container">
392
+ <!-- Simplified header with controls -->
393
+ <div class="code-header-compact">
394
+ <div class="header-left">
395
+ <button id="code-expand-all" class="btn-compact" title="Expand All">⊕</button>
396
+ <button id="code-collapse-all" class="btn-compact" title="Collapse All">⊖</button>
397
+ <button id="code-reset-zoom" class="btn-compact" title="Reset Zoom">⟲</button>
398
+ <button id="code-toggle-legend" class="btn-compact" title="Toggle Legend">ℹ️</button>
399
+ </div>
400
+ <div class="header-center">
401
+ <span class="stat-compact">📁 <span id="file-count">0</span></span>
402
+ <span class="stat-compact">🏛️ <span id="class-count">0</span></span>
403
+ <span class="stat-compact">⚡ <span id="function-count">0</span></span>
404
+ <span class="stat-compact">📝 <span id="line-count">0</span></span>
405
+ </div>
406
+ <div class="header-right">
407
+ <select id="language-filter" class="select-compact">
408
+ <option value="all">All</option>
409
+ <option value="python">Python</option>
410
+ <option value="javascript">JS</option>
411
+ <option value="typescript">TS</option>
412
+ </select>
413
+ <input type="text" id="code-search" placeholder="Search..." class="search-compact">
414
+ </div>
415
+ </div>
416
+ <!-- Advanced options - visible by default -->
417
+ <div class="code-advanced-options-visible">
418
+ <div class="advanced-content">
419
+ <div class="option-group">
420
+ <label>Languages:</label>
421
+ <label><input type="checkbox" class="language-checkbox" value="python" checked> Python</label>
422
+ <label><input type="checkbox" class="language-checkbox" value="javascript" checked> JS</label>
423
+ <label><input type="checkbox" class="language-checkbox" value="typescript" checked> TS</label>
424
+ </div>
425
+ <div class="option-group">
426
+ <label>Ignore: <input type="text" id="ignore-patterns" placeholder="test*, *.spec.js, node_modules" class="input-compact" style="width: 200px;"></label>
427
+ </div>
428
+ <div class="option-group">
429
+ <label><input type="checkbox" id="show-hidden-files"> Show hidden files (dotfiles)</label>
430
+ </div>
431
+ </div>
432
+ </div>
433
+ <div id="code-tree-container" class="code-tree-container">
434
+ <div id="code-tree"></div>
435
+ <!-- Collapsible legend -->
436
+ <div class="tree-legend collapsed" id="tree-legend" style="display: none;">
437
+ <button class="legend-close" onclick="document.getElementById('tree-legend').style.display='none'">✕</button>
438
+ <div class="legend-content">
439
+ <div class="legend-column">
440
+ <div class="legend-item"><span class="legend-icon">📦</span> Module</div>
441
+ <div class="legend-item"><span class="legend-icon">🏛️</span> Class</div>
442
+ <div class="legend-item"><span class="legend-icon">⚡</span> Function</div>
443
+ <div class="legend-item"><span class="legend-icon">🔧</span> Method</div>
444
+ </div>
445
+ <div class="legend-column">
446
+ <div class="legend-item"><span class="legend-icon complexity-low">●</span> Low</div>
447
+ <div class="legend-item"><span class="legend-icon complexity-medium">●</span> Med</div>
448
+ <div class="legend-item"><span class="legend-icon complexity-high">●</span> High</div>
449
+ </div>
450
+ </div>
451
+ </div>
452
+ </div>
453
+ <div class="code-breadcrumb" id="code-breadcrumb">
454
+ <div class="breadcrumb-ticker" id="breadcrumb-ticker">
455
+ <span id="breadcrumb-content">Ready to analyze...</span>
456
+ </div>
457
+ </div>
458
+ </div>
459
+ </div>
460
+
319
461
  </div>
320
462
  </div>
321
463
  </div>
322
464
  </div>
323
465
 
466
+ <!-- Code Viewer Modal -->
467
+ <div id="code-viewer-modal" class="modal" style="display: none;">
468
+ <div class="modal-content">
469
+ <div class="modal-header">
470
+ <h2 id="code-viewer-title">Code Viewer</h2>
471
+ <button class="close" onclick="closeCodeViewer()">&times;</button>
472
+ </div>
473
+ <div class="modal-body">
474
+ <pre><code id="code-viewer-content"></code></pre>
475
+ </div>
476
+ <div class="modal-footer">
477
+ <div class="code-viewer-info">
478
+ <span id="code-viewer-path"></span>
479
+ <span id="code-viewer-lines"></span>
480
+ <span id="code-viewer-language"></span>
481
+ </div>
482
+ <button onclick="closeCodeViewer()">Close</button>
483
+ </div>
484
+ </div>
485
+ </div>
486
+
324
487
  <!-- Footer -->
325
488
  <div class="footer">
326
489
  <div class="footer-content">
@@ -338,11 +501,26 @@
338
501
  <span class="footer-label">Branch:</span>
339
502
  <span class="footer-value" id="footer-git-branch">Unknown</span>
340
503
  </div>
504
+ <!-- Analysis Status (hidden by default) -->
505
+ <div class="footer-item" id="footer-analysis-container" style="display: none;">
506
+ <span class="footer-divider">|</span>
507
+ <span class="footer-label">Analysis:</span>
508
+ <span class="footer-value" id="footer-analysis-status">
509
+ <span class="analysis-progress" id="footer-analysis-progress"></span>
510
+ </span>
511
+ </div>
341
512
  </div>
342
513
  </div>
343
514
 
344
515
  <!-- JavaScript Modules -->
345
516
  <!-- Load bundled dashboard assets (built with Vite) -->
346
517
  <script type="module" src="/static/dist/dashboard.js"></script>
518
+
519
+ <!-- Activity Tree Module (from Vite build) -->
520
+ <script type="module" src="/static/dist/components/activity-tree.js"></script>
521
+
522
+ <!-- Code Tree Module (from Vite build) -->
523
+ <script type="module" src="/static/dist/components/code-tree.js"></script>
524
+ <script type="module" src="/static/dist/components/code-viewer.js"></script>
347
525
  </body>
348
526
  </html>
@@ -12,15 +12,21 @@ WHY service-oriented approach:
12
12
  - Easier testing and maintenance
13
13
  - Reduced file size from 1040 to ~400 lines
14
14
  - Clear service boundaries and responsibilities
15
+
16
+ NOTE: Requires Claude Code version 1.0.92 or higher for proper hook support.
17
+ Earlier versions do not support matcher-based hook configuration.
15
18
  """
16
19
 
17
20
  import json
18
21
  import os
22
+ import re
19
23
  import select
20
24
  import signal
25
+ import subprocess
21
26
  import sys
22
27
  import threading
23
28
  from datetime import datetime
29
+ from typing import Optional, Tuple
24
30
 
25
31
  # Import extracted modules with fallback for direct execution
26
32
  try:
@@ -51,10 +57,27 @@ except ImportError:
51
57
  SubagentResponseProcessor,
52
58
  )
53
59
 
54
- # Debug mode is enabled by default for better visibility into hook processing
55
- # Set CLAUDE_MPM_HOOK_DEBUG=false to disable debug output
60
+ """
61
+ Debug mode configuration for hook processing.
62
+
63
+ WHY enabled by default: Hook processing can be complex and hard to debug.
64
+ Having debug output available by default helps diagnose issues during development.
65
+ Production deployments can disable via environment variable.
66
+
67
+ Performance Impact: Debug logging adds ~5-10% overhead but provides crucial
68
+ visibility into event flow, timing, and error conditions.
69
+ """
56
70
  DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
57
71
 
72
+ """
73
+ Conditional imports with graceful fallbacks for testing and modularity.
74
+
75
+ WHY conditional imports:
76
+ - EventBus is optional for basic hook functionality
77
+ - Tests may not have full environment setup
78
+ - Allows hooks to work in minimal configurations
79
+ - Graceful degradation when dependencies unavailable
80
+ """
58
81
  # Import EventBus availability flag for backward compatibility with tests
59
82
  try:
60
83
  from claude_mpm.services.event_bus import EventBus
@@ -70,10 +93,125 @@ try:
70
93
  except ImportError:
71
94
  get_connection_pool = None
72
95
 
73
- # Global singleton handler instance
96
+ """
97
+ Global singleton pattern for hook handler.
98
+
99
+ WHY singleton:
100
+ - Only one handler should process Claude Code events
101
+ - Maintains consistent state across all hook invocations
102
+ - Prevents duplicate event processing
103
+ - Thread-safe initialization with lock
104
+
105
+ GOTCHA: Must use get_global_handler() not direct access to avoid race conditions.
106
+ """
74
107
  _global_handler = None
75
108
  _handler_lock = threading.Lock()
76
109
 
110
+ """
111
+ Version compatibility checking.
112
+
113
+ WHY version checking:
114
+ - Claude Code hook support was added in v1.0.92
115
+ - Earlier versions don't support matcher-based configuration
116
+ - Prevents confusing errors with unsupported versions
117
+
118
+ Security: Version checking prevents execution on incompatible environments.
119
+ """
120
+ MIN_CLAUDE_VERSION = "1.0.92"
121
+
122
+
123
+ def check_claude_version() -> Tuple[bool, Optional[str]]:
124
+ """
125
+ Verify Claude Code version compatibility for hook support.
126
+
127
+ Executes 'claude --version' command to detect installed version and
128
+ compares against minimum required version for hook functionality.
129
+
130
+ Version Checking Logic:
131
+ 1. Execute 'claude --version' with timeout
132
+ 2. Parse version string using regex
133
+ 3. Compare against MIN_CLAUDE_VERSION (1.0.92)
134
+ 4. Return compatibility status and detected version
135
+
136
+ WHY this check is critical:
137
+ - Hook support was added in Claude Code v1.0.92
138
+ - Earlier versions don't understand matcher-based hooks
139
+ - Prevents cryptic errors from unsupported configurations
140
+ - Allows graceful fallback or user notification
141
+
142
+ Error Handling:
143
+ - Command timeout after 5 seconds
144
+ - Subprocess errors caught and logged
145
+ - Invalid version formats handled gracefully
146
+ - Returns (False, None) on any failure
147
+
148
+ Performance Notes:
149
+ - Subprocess call has ~100ms overhead
150
+ - Result should be cached by caller
151
+ - Only called during initialization
152
+
153
+ Returns:
154
+ Tuple[bool, Optional[str]]:
155
+ - bool: True if version is compatible
156
+ - str|None: Detected version string, None if detection failed
157
+
158
+ Examples:
159
+ >>> is_compatible, version = check_claude_version()
160
+ >>> if not is_compatible:
161
+ ... print(f"Claude Code {version or 'unknown'} is not supported")
162
+ """
163
+ try:
164
+ # Try to detect Claude Code version
165
+ result = subprocess.run(
166
+ ["claude", "--version"],
167
+ capture_output=True,
168
+ text=True,
169
+ timeout=5,
170
+ check=False,
171
+ )
172
+
173
+ if result.returncode == 0:
174
+ version_text = result.stdout.strip()
175
+ # Extract version number (e.g., "1.0.92 (Claude Code)" -> "1.0.92")
176
+ match = re.match(r"^([\d\.]+)", version_text)
177
+ if match:
178
+ version = match.group(1)
179
+
180
+ # Compare versions
181
+ def parse_version(v: str):
182
+ try:
183
+ return [int(x) for x in v.split(".")]
184
+ except (ValueError, AttributeError):
185
+ return [0]
186
+
187
+ current = parse_version(version)
188
+ required = parse_version(MIN_CLAUDE_VERSION)
189
+
190
+ # Check if current version meets minimum
191
+ for i in range(max(len(current), len(required))):
192
+ curr_part = current[i] if i < len(current) else 0
193
+ req_part = required[i] if i < len(required) else 0
194
+
195
+ if curr_part < req_part:
196
+ if DEBUG:
197
+ print(
198
+ f"⚠️ Claude Code {version} does not support matcher-based hooks "
199
+ f"(requires {MIN_CLAUDE_VERSION}+). Hook monitoring disabled.",
200
+ file=sys.stderr,
201
+ )
202
+ return False, version
203
+ if curr_part > req_part:
204
+ return True, version
205
+
206
+ return True, version
207
+ except Exception as e:
208
+ if DEBUG:
209
+ print(
210
+ f"Warning: Could not detect Claude Code version: {e}", file=sys.stderr
211
+ )
212
+
213
+ return False, None
214
+
77
215
 
78
216
  class ClaudeHookHandler:
79
217
  """Refactored hook handler with service-oriented architecture.
@@ -111,6 +249,10 @@ class ClaudeHookHandler:
111
249
  self.delegation_requests = self.state_manager.delegation_requests
112
250
  self.pending_prompts = self.state_manager.pending_prompts
113
251
 
252
+ # Initialize git branch cache (used by event_handlers)
253
+ self._git_branch_cache = {}
254
+ self._git_branch_cache_time = {}
255
+
114
256
  def handle(self):
115
257
  """Process hook event with minimal overhead and timeout protection.
116
258
 
@@ -225,7 +367,16 @@ class ClaudeHookHandler:
225
367
  # Empty or whitespace-only data
226
368
  return None
227
369
 
228
- return json.loads(event_data)
370
+ parsed = json.loads(event_data)
371
+ # Debug: Log the actual event format we receive
372
+ if DEBUG:
373
+ print(
374
+ f"Received event with keys: {list(parsed.keys())}", file=sys.stderr
375
+ )
376
+ for key in ["hook_event_name", "event", "type", "event_type"]:
377
+ if key in parsed:
378
+ print(f" {key} = '{parsed[key]}'", file=sys.stderr)
379
+ return parsed
229
380
  except (json.JSONDecodeError, ValueError) as e:
230
381
  if DEBUG:
231
382
  print(f"Failed to parse hook event: {e}", file=sys.stderr)
@@ -245,7 +396,20 @@ class ClaudeHookHandler:
245
396
  Args:
246
397
  event: Hook event dictionary
247
398
  """
248
- hook_type = event.get("hook_event_name", "unknown")
399
+ # Try multiple field names for compatibility
400
+ hook_type = (
401
+ event.get("hook_event_name")
402
+ or event.get("event")
403
+ or event.get("type")
404
+ or event.get("event_type")
405
+ or event.get("hook_event_type")
406
+ or "unknown"
407
+ )
408
+
409
+ # Log the actual event structure for debugging
410
+ if DEBUG and hook_type == "unknown":
411
+ print(f"Unknown event format, keys: {list(event.keys())}", file=sys.stderr)
412
+ print(f"Event sample: {str(event)[:200]}", file=sys.stderr)
249
413
 
250
414
  # Map event types to handlers
251
415
  event_handlers = {
@@ -316,6 +480,19 @@ def main():
316
480
  global _global_handler
317
481
  _continue_printed = False # Track if we've already printed continue
318
482
 
483
+ # Check Claude Code version compatibility first
484
+ is_compatible, version = check_claude_version()
485
+ if not is_compatible:
486
+ # Version incompatible - just continue without processing
487
+ # This prevents errors on older Claude Code versions
488
+ if DEBUG and version:
489
+ print(
490
+ f"Skipping hook processing due to version incompatibility ({version})",
491
+ file=sys.stderr,
492
+ )
493
+ print(json.dumps({"action": "continue"}))
494
+ sys.exit(0)
495
+
319
496
  def cleanup_handler(signum=None, frame=None):
320
497
  """Cleanup handler for signals and exit."""
321
498
  nonlocal _continue_printed