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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/INSTRUCTIONS.md +26 -1
- claude_mpm/agents/agents_metadata.py +57 -0
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
- claude_mpm/agents/templates/agent-manager.json +263 -17
- claude_mpm/agents/templates/agentic_coder_optimizer.json +222 -0
- claude_mpm/agents/templates/code_analyzer.json +18 -8
- claude_mpm/agents/templates/engineer.json +1 -1
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/research.json +1 -1
- claude_mpm/cli/__init__.py +15 -0
- claude_mpm/cli/commands/__init__.py +6 -0
- claude_mpm/cli/commands/analyze.py +548 -0
- claude_mpm/cli/commands/analyze_code.py +524 -0
- claude_mpm/cli/commands/configure.py +78 -28
- claude_mpm/cli/commands/configure_tui.py +62 -60
- claude_mpm/cli/commands/dashboard.py +288 -0
- claude_mpm/cli/commands/debug.py +1386 -0
- claude_mpm/cli/commands/mpm_init.py +427 -0
- claude_mpm/cli/commands/mpm_init_handler.py +83 -0
- claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
- claude_mpm/cli/parsers/analyze_parser.py +135 -0
- claude_mpm/cli/parsers/base_parser.py +44 -0
- claude_mpm/cli/parsers/dashboard_parser.py +113 -0
- claude_mpm/cli/parsers/debug_parser.py +319 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +122 -0
- claude_mpm/constants.py +13 -1
- claude_mpm/core/framework_loader.py +148 -6
- claude_mpm/core/log_manager.py +16 -13
- claude_mpm/core/logger.py +1 -1
- claude_mpm/core/unified_agent_registry.py +1 -1
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
- claude_mpm/dashboard/analysis_runner.py +455 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/built/dashboard.js +1 -1
- claude_mpm/dashboard/static/built/socket-client.js +1 -1
- claude_mpm/dashboard/static/css/activity.css +549 -0
- claude_mpm/dashboard/static/css/code-tree.css +1175 -0
- claude_mpm/dashboard/static/css/dashboard.css +245 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/js/components/activity-tree.js +1338 -0
- claude_mpm/dashboard/static/js/components/code-tree.js +2535 -0
- claude_mpm/dashboard/static/js/components/code-viewer.js +480 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +59 -9
- claude_mpm/dashboard/static/js/components/session-manager.js +40 -4
- claude_mpm/dashboard/static/js/components/socket-manager.js +12 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +4 -0
- claude_mpm/dashboard/static/js/components/working-directory.js +17 -1
- claude_mpm/dashboard/static/js/dashboard.js +51 -0
- claude_mpm/dashboard/static/js/socket-client.js +465 -29
- claude_mpm/dashboard/templates/index.html +182 -4
- claude_mpm/hooks/claude_hooks/hook_handler.py +182 -5
- claude_mpm/hooks/claude_hooks/installer.py +386 -113
- claude_mpm/scripts/claude-hook-handler.sh +161 -0
- claude_mpm/scripts/socketio_daemon.py +121 -8
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +2 -2
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -2
- claude_mpm/services/agents/memory/memory_format_service.py +1 -3
- claude_mpm/services/cli/agent_cleanup_service.py +1 -5
- claude_mpm/services/cli/agent_dependency_service.py +1 -1
- claude_mpm/services/cli/agent_validation_service.py +3 -4
- claude_mpm/services/cli/dashboard_launcher.py +2 -3
- claude_mpm/services/cli/startup_checker.py +0 -11
- claude_mpm/services/core/cache_manager.py +1 -3
- claude_mpm/services/core/path_resolver.py +1 -4
- claude_mpm/services/core/service_container.py +2 -2
- claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
- claude_mpm/services/infrastructure/monitoring/__init__.py +11 -11
- claude_mpm/services/infrastructure/monitoring.py +11 -11
- claude_mpm/services/project/architecture_analyzer.py +1 -1
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/language_analyzer.py +3 -3
- claude_mpm/services/project/metrics_collector.py +3 -6
- claude_mpm/services/socketio/event_normalizer.py +64 -0
- claude_mpm/services/socketio/handlers/__init__.py +2 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +672 -0
- claude_mpm/services/socketio/handlers/registry.py +2 -0
- claude_mpm/services/socketio/server/connection_manager.py +6 -4
- claude_mpm/services/socketio/server/core.py +100 -11
- claude_mpm/services/socketio/server/main.py +8 -2
- claude_mpm/services/visualization/__init__.py +19 -0
- claude_mpm/services/visualization/mermaid_generator.py +938 -0
- claude_mpm/tools/__main__.py +208 -0
- claude_mpm/tools/code_tree_analyzer.py +1596 -0
- claude_mpm/tools/code_tree_builder.py +631 -0
- claude_mpm/tools/code_tree_events.py +416 -0
- claude_mpm/tools/socketio_debug.py +671 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/METADATA +2 -1
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/RECORD +110 -74
- claude_mpm/agents/schema/agent_schema.json +0 -314
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Code Analysis Runner for Dashboard
|
|
4
|
+
===================================
|
|
5
|
+
|
|
6
|
+
WHY: Manages subprocess execution of code analysis, streaming results to
|
|
7
|
+
Socket.IO clients in real-time while handling cancellation and error recovery.
|
|
8
|
+
|
|
9
|
+
DESIGN DECISIONS:
|
|
10
|
+
- Use subprocess for isolation and cancellation support
|
|
11
|
+
- Stream output line-by-line for real-time updates
|
|
12
|
+
- Queue multiple analysis requests
|
|
13
|
+
- Handle process lifecycle management
|
|
14
|
+
- Convert analyzer events to Socket.IO events
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
import subprocess
|
|
20
|
+
import sys
|
|
21
|
+
import threading
|
|
22
|
+
from dataclasses import asdict, dataclass
|
|
23
|
+
from datetime import datetime
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from queue import Queue
|
|
26
|
+
from typing import Any, Dict, List, Optional
|
|
27
|
+
|
|
28
|
+
from ..core.logging_config import get_logger
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class AnalysisRequest:
|
|
33
|
+
"""Represents a code analysis request."""
|
|
34
|
+
|
|
35
|
+
request_id: str
|
|
36
|
+
path: str
|
|
37
|
+
languages: Optional[List[str]] = None
|
|
38
|
+
max_depth: Optional[int] = None
|
|
39
|
+
ignore_patterns: Optional[List[str]] = None
|
|
40
|
+
timestamp: datetime = None
|
|
41
|
+
|
|
42
|
+
def __post_init__(self):
|
|
43
|
+
if self.timestamp is None:
|
|
44
|
+
self.timestamp = datetime.utcnow()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class CodeAnalysisRunner:
|
|
48
|
+
"""Manages code analysis subprocess execution for the dashboard.
|
|
49
|
+
|
|
50
|
+
WHY: Provides isolation between the dashboard server and analysis process,
|
|
51
|
+
allowing for cancellation, resource limits, and crash recovery.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, socketio_server):
|
|
55
|
+
"""Initialize the analysis runner.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
socketio_server: SocketIOServer instance for broadcasting events
|
|
59
|
+
"""
|
|
60
|
+
self.logger = get_logger(__name__)
|
|
61
|
+
self.server = socketio_server
|
|
62
|
+
self.current_process = None
|
|
63
|
+
self.current_request = None
|
|
64
|
+
self.request_queue = Queue()
|
|
65
|
+
self.running = False
|
|
66
|
+
self.worker_thread = None
|
|
67
|
+
self.cancel_event = threading.Event()
|
|
68
|
+
|
|
69
|
+
# Statistics
|
|
70
|
+
self.stats = {
|
|
71
|
+
"analyses_started": 0,
|
|
72
|
+
"analyses_completed": 0,
|
|
73
|
+
"analyses_cancelled": 0,
|
|
74
|
+
"analyses_failed": 0,
|
|
75
|
+
"total_files": 0,
|
|
76
|
+
"total_nodes": 0,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
def start(self):
|
|
80
|
+
"""Start the analysis runner worker thread."""
|
|
81
|
+
if self.running:
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
self.running = True
|
|
85
|
+
self.cancel_event.clear()
|
|
86
|
+
self.worker_thread = threading.Thread(target=self._worker_loop, daemon=True)
|
|
87
|
+
self.worker_thread.start()
|
|
88
|
+
self.logger.info("Code analysis runner started")
|
|
89
|
+
|
|
90
|
+
def stop(self):
|
|
91
|
+
"""Stop the analysis runner and cleanup."""
|
|
92
|
+
self.running = False
|
|
93
|
+
self.cancel_current()
|
|
94
|
+
|
|
95
|
+
# Add sentinel to queue to wake up worker
|
|
96
|
+
self.request_queue.put(None)
|
|
97
|
+
|
|
98
|
+
if self.worker_thread:
|
|
99
|
+
self.worker_thread.join(timeout=5)
|
|
100
|
+
|
|
101
|
+
self.logger.info("Code analysis runner stopped")
|
|
102
|
+
|
|
103
|
+
def request_analysis(
|
|
104
|
+
self,
|
|
105
|
+
request_id: str,
|
|
106
|
+
path: str,
|
|
107
|
+
languages: Optional[List[str]] = None,
|
|
108
|
+
max_depth: Optional[int] = None,
|
|
109
|
+
ignore_patterns: Optional[List[str]] = None,
|
|
110
|
+
) -> bool:
|
|
111
|
+
"""Queue a new analysis request.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
request_id: Unique request identifier
|
|
115
|
+
path: Directory path to analyze
|
|
116
|
+
languages: Optional list of languages to filter
|
|
117
|
+
max_depth: Optional maximum directory depth
|
|
118
|
+
ignore_patterns: Optional list of patterns to ignore
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
True if request was queued successfully
|
|
122
|
+
"""
|
|
123
|
+
# Validate path
|
|
124
|
+
analysis_path = Path(path).resolve()
|
|
125
|
+
if not analysis_path.exists():
|
|
126
|
+
self._emit_error(request_id, f"Path does not exist: {path}")
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
if not analysis_path.is_dir():
|
|
130
|
+
self._emit_error(request_id, f"Path is not a directory: {path}")
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
# Create request
|
|
134
|
+
request = AnalysisRequest(
|
|
135
|
+
request_id=request_id,
|
|
136
|
+
path=str(analysis_path),
|
|
137
|
+
languages=languages,
|
|
138
|
+
max_depth=max_depth,
|
|
139
|
+
ignore_patterns=ignore_patterns,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Queue request
|
|
143
|
+
self.request_queue.put(request)
|
|
144
|
+
self.logger.info(f"Queued analysis request {request_id} for {path}")
|
|
145
|
+
|
|
146
|
+
# Emit queued event
|
|
147
|
+
self._emit_event(
|
|
148
|
+
"code:analysis:queued",
|
|
149
|
+
{
|
|
150
|
+
"request_id": request_id,
|
|
151
|
+
"path": str(analysis_path),
|
|
152
|
+
"queue_size": self.request_queue.qsize(),
|
|
153
|
+
},
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return True
|
|
157
|
+
|
|
158
|
+
def cancel_current(self):
|
|
159
|
+
"""Cancel the currently running analysis."""
|
|
160
|
+
if self.current_process and self.current_process.poll() is None:
|
|
161
|
+
self.cancel_event.set()
|
|
162
|
+
|
|
163
|
+
# Try graceful termination first
|
|
164
|
+
self.current_process.terminate()
|
|
165
|
+
try:
|
|
166
|
+
self.current_process.wait(timeout=2)
|
|
167
|
+
except subprocess.TimeoutExpired:
|
|
168
|
+
# Force kill if needed
|
|
169
|
+
self.current_process.kill()
|
|
170
|
+
self.current_process.wait()
|
|
171
|
+
|
|
172
|
+
self.stats["analyses_cancelled"] += 1
|
|
173
|
+
|
|
174
|
+
if self.current_request:
|
|
175
|
+
self._emit_event(
|
|
176
|
+
"code:analysis:cancelled",
|
|
177
|
+
{
|
|
178
|
+
"request_id": self.current_request.request_id,
|
|
179
|
+
"path": self.current_request.path,
|
|
180
|
+
},
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
self.logger.info("Cancelled current analysis")
|
|
184
|
+
|
|
185
|
+
def get_status(self) -> Dict[str, Any]:
|
|
186
|
+
"""Get current runner status.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Dictionary with current status and statistics
|
|
190
|
+
"""
|
|
191
|
+
return {
|
|
192
|
+
"running": self.running,
|
|
193
|
+
"current_request": (
|
|
194
|
+
asdict(self.current_request) if self.current_request else None
|
|
195
|
+
),
|
|
196
|
+
"queue_size": self.request_queue.qsize(),
|
|
197
|
+
"stats": self.stats.copy(),
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
def _worker_loop(self):
|
|
201
|
+
"""Worker thread loop for processing analysis requests."""
|
|
202
|
+
while self.running:
|
|
203
|
+
try:
|
|
204
|
+
# Get next request (blocking with timeout)
|
|
205
|
+
request = self.request_queue.get(timeout=1)
|
|
206
|
+
|
|
207
|
+
if request is None: # Sentinel value
|
|
208
|
+
break
|
|
209
|
+
|
|
210
|
+
# Reset cancel event
|
|
211
|
+
self.cancel_event.clear()
|
|
212
|
+
|
|
213
|
+
# Process request
|
|
214
|
+
self._process_request(request)
|
|
215
|
+
|
|
216
|
+
except Exception as e:
|
|
217
|
+
self.logger.error(f"Error in worker loop: {e}")
|
|
218
|
+
|
|
219
|
+
def _process_request(self, request: AnalysisRequest):
|
|
220
|
+
"""Process a single analysis request.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
request: The analysis request to process
|
|
224
|
+
"""
|
|
225
|
+
self.current_request = request
|
|
226
|
+
self.stats["analyses_started"] += 1
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
# Emit start event
|
|
230
|
+
self._emit_event(
|
|
231
|
+
"code:analysis:start",
|
|
232
|
+
{
|
|
233
|
+
"request_id": request.request_id,
|
|
234
|
+
"path": request.path,
|
|
235
|
+
"languages": request.languages,
|
|
236
|
+
"timestamp": request.timestamp.isoformat(),
|
|
237
|
+
},
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# Build command
|
|
241
|
+
cmd = self._build_command(request)
|
|
242
|
+
self.logger.info(f"Starting analysis subprocess: {' '.join(cmd)}")
|
|
243
|
+
|
|
244
|
+
# Start subprocess
|
|
245
|
+
try:
|
|
246
|
+
self.current_process = subprocess.Popen(
|
|
247
|
+
cmd,
|
|
248
|
+
stdout=subprocess.PIPE,
|
|
249
|
+
stderr=subprocess.PIPE,
|
|
250
|
+
text=True,
|
|
251
|
+
bufsize=1,
|
|
252
|
+
universal_newlines=True,
|
|
253
|
+
env=self._get_subprocess_env(),
|
|
254
|
+
)
|
|
255
|
+
self.logger.debug(
|
|
256
|
+
f"Subprocess started with PID: {self.current_process.pid}"
|
|
257
|
+
)
|
|
258
|
+
except FileNotFoundError as e:
|
|
259
|
+
raise subprocess.SubprocessError(
|
|
260
|
+
f"Python executable not found: {cmd[0]}"
|
|
261
|
+
) from e
|
|
262
|
+
except Exception as e:
|
|
263
|
+
raise subprocess.SubprocessError(
|
|
264
|
+
f"Failed to start subprocess: {e}"
|
|
265
|
+
) from e
|
|
266
|
+
|
|
267
|
+
# Process output
|
|
268
|
+
self._process_output(request)
|
|
269
|
+
|
|
270
|
+
# Wait for completion
|
|
271
|
+
return_code = self.current_process.wait()
|
|
272
|
+
|
|
273
|
+
if self.cancel_event.is_set():
|
|
274
|
+
# Analysis was cancelled
|
|
275
|
+
pass # Event already emitted in cancel_current
|
|
276
|
+
elif return_code == 0:
|
|
277
|
+
# Success
|
|
278
|
+
self.stats["analyses_completed"] += 1
|
|
279
|
+
self._emit_event(
|
|
280
|
+
"code:analysis:complete",
|
|
281
|
+
{
|
|
282
|
+
"request_id": request.request_id,
|
|
283
|
+
"path": request.path,
|
|
284
|
+
"stats": {
|
|
285
|
+
"total_files": self.stats["total_files"],
|
|
286
|
+
"total_nodes": self.stats["total_nodes"],
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
)
|
|
290
|
+
else:
|
|
291
|
+
# Failure - capture any remaining stderr
|
|
292
|
+
stderr_output = ""
|
|
293
|
+
if self.current_process.stderr:
|
|
294
|
+
try:
|
|
295
|
+
# Read any remaining stderr output
|
|
296
|
+
stderr_lines = []
|
|
297
|
+
for line in self.current_process.stderr:
|
|
298
|
+
stderr_lines.append(line.strip())
|
|
299
|
+
stderr_output = "\n".join(stderr_lines)
|
|
300
|
+
except Exception as e:
|
|
301
|
+
stderr_output = f"Failed to read stderr: {e}"
|
|
302
|
+
|
|
303
|
+
self.stats["analyses_failed"] += 1
|
|
304
|
+
error_msg = f"Analysis failed with code {return_code}"
|
|
305
|
+
if stderr_output:
|
|
306
|
+
error_msg += f": {stderr_output}"
|
|
307
|
+
|
|
308
|
+
self.logger.error(f"Subprocess failed: {error_msg}")
|
|
309
|
+
self._emit_error(request.request_id, error_msg)
|
|
310
|
+
|
|
311
|
+
except subprocess.SubprocessError as e:
|
|
312
|
+
self.logger.error(f"Subprocess error for request {request.request_id}: {e}")
|
|
313
|
+
self.stats["analyses_failed"] += 1
|
|
314
|
+
self._emit_error(request.request_id, f"Failed to start analyzer: {e}")
|
|
315
|
+
except Exception as e:
|
|
316
|
+
self.logger.error(
|
|
317
|
+
f"Error processing request {request.request_id}: {e}", exc_info=True
|
|
318
|
+
)
|
|
319
|
+
self.stats["analyses_failed"] += 1
|
|
320
|
+
self._emit_error(request.request_id, str(e))
|
|
321
|
+
|
|
322
|
+
finally:
|
|
323
|
+
self.current_process = None
|
|
324
|
+
self.current_request = None
|
|
325
|
+
|
|
326
|
+
def _build_command(self, request: AnalysisRequest) -> List[str]:
|
|
327
|
+
"""Build the subprocess command for analysis.
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
request: The analysis request
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
Command list for subprocess.Popen
|
|
334
|
+
"""
|
|
335
|
+
# Get Python executable
|
|
336
|
+
python_exe = sys.executable
|
|
337
|
+
|
|
338
|
+
# Build command - use the CLI analyze-code command
|
|
339
|
+
cmd = [
|
|
340
|
+
python_exe,
|
|
341
|
+
"-m",
|
|
342
|
+
"claude_mpm",
|
|
343
|
+
"analyze-code",
|
|
344
|
+
request.path,
|
|
345
|
+
"--emit-events",
|
|
346
|
+
"--output",
|
|
347
|
+
"json",
|
|
348
|
+
]
|
|
349
|
+
|
|
350
|
+
# Add optional parameters
|
|
351
|
+
if request.languages:
|
|
352
|
+
cmd.extend(["--languages", ",".join(request.languages)])
|
|
353
|
+
|
|
354
|
+
if request.max_depth:
|
|
355
|
+
cmd.extend(["--max-depth", str(request.max_depth)])
|
|
356
|
+
|
|
357
|
+
if request.ignore_patterns:
|
|
358
|
+
for pattern in request.ignore_patterns:
|
|
359
|
+
cmd.extend(["--ignore", pattern])
|
|
360
|
+
|
|
361
|
+
return cmd
|
|
362
|
+
|
|
363
|
+
def _get_subprocess_env(self) -> Dict[str, str]:
|
|
364
|
+
"""Get environment variables for subprocess.
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
Environment dictionary for subprocess
|
|
368
|
+
"""
|
|
369
|
+
env = os.environ.copy()
|
|
370
|
+
|
|
371
|
+
# Ensure Socket.IO URL is set for event emission
|
|
372
|
+
env["SOCKETIO_URL"] = f"http://localhost:{self.server.port}"
|
|
373
|
+
|
|
374
|
+
# Set Python path to include our modules
|
|
375
|
+
python_path = env.get("PYTHONPATH", "")
|
|
376
|
+
src_path = str(Path(__file__).parent.parent.parent)
|
|
377
|
+
if src_path not in python_path:
|
|
378
|
+
env["PYTHONPATH"] = f"{src_path}:{python_path}" if python_path else src_path
|
|
379
|
+
|
|
380
|
+
return env
|
|
381
|
+
|
|
382
|
+
def _process_output(self, request: AnalysisRequest):
|
|
383
|
+
"""Process subprocess output and emit events.
|
|
384
|
+
|
|
385
|
+
Args:
|
|
386
|
+
request: The current analysis request
|
|
387
|
+
"""
|
|
388
|
+
if not self.current_process:
|
|
389
|
+
return
|
|
390
|
+
|
|
391
|
+
# Read output line by line
|
|
392
|
+
for line in iter(self.current_process.stdout.readline, ""):
|
|
393
|
+
if self.cancel_event.is_set():
|
|
394
|
+
break
|
|
395
|
+
|
|
396
|
+
line = line.strip()
|
|
397
|
+
if not line:
|
|
398
|
+
continue
|
|
399
|
+
|
|
400
|
+
try:
|
|
401
|
+
# Parse JSON event
|
|
402
|
+
event = json.loads(line)
|
|
403
|
+
|
|
404
|
+
# Route event to appropriate handler
|
|
405
|
+
event_type = event.get("type")
|
|
406
|
+
event_data = event.get("data", {})
|
|
407
|
+
|
|
408
|
+
# Add request ID to event data
|
|
409
|
+
event_data["request_id"] = request.request_id
|
|
410
|
+
|
|
411
|
+
# Update statistics based on event type
|
|
412
|
+
if event_type == "code:file:complete":
|
|
413
|
+
self.stats["total_files"] += 1
|
|
414
|
+
elif event_type == "code:node:found":
|
|
415
|
+
self.stats["total_nodes"] += 1
|
|
416
|
+
|
|
417
|
+
# Emit to Socket.IO clients
|
|
418
|
+
self._emit_event(event_type, event_data)
|
|
419
|
+
|
|
420
|
+
except json.JSONDecodeError:
|
|
421
|
+
# Not JSON, treat as log message
|
|
422
|
+
self.logger.debug(f"Analyzer output: {line}")
|
|
423
|
+
except Exception as e:
|
|
424
|
+
self.logger.warning(f"Error processing analyzer output: {e}")
|
|
425
|
+
|
|
426
|
+
def _emit_event(self, event_type: str, data: Dict[str, Any]):
|
|
427
|
+
"""Emit an event to Socket.IO clients.
|
|
428
|
+
|
|
429
|
+
Args:
|
|
430
|
+
event_type: Type of event
|
|
431
|
+
data: Event data
|
|
432
|
+
"""
|
|
433
|
+
if self.server:
|
|
434
|
+
# Add timestamp if not present
|
|
435
|
+
if "timestamp" not in data:
|
|
436
|
+
data["timestamp"] = datetime.utcnow().isoformat()
|
|
437
|
+
|
|
438
|
+
# Broadcast to all clients
|
|
439
|
+
self.server.broadcast_event(event_type, data)
|
|
440
|
+
|
|
441
|
+
def _emit_error(self, request_id: str, message: str):
|
|
442
|
+
"""Emit an error event.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
request_id: Request that caused the error
|
|
446
|
+
message: Error message
|
|
447
|
+
"""
|
|
448
|
+
self._emit_event(
|
|
449
|
+
"code:analysis:error",
|
|
450
|
+
{
|
|
451
|
+
"request_id": request_id,
|
|
452
|
+
"message": message,
|
|
453
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
454
|
+
},
|
|
455
|
+
)
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
class t{constructor(){this.container=null,this.svg=null,this.treeData=null,this.root=null,this.treeLayout=null,this.treeGroup=null,this.events=[],this.todoWriteStack=[],this.activeAgent=null,this.activeAgentStack=[],this.margin={top:20,right:120,bottom:20,left:120},this.width=960-this.margin.left-this.margin.right,this.height=500-this.margin.top-this.margin.bottom,this.nodeId=0,this.duration=750,this.timeRange="30min",this.searchTerm="",this.tooltip=null,this.initialized=!1}initialize(){if(console.log("ActivityTree.initialize() called, initialized:",this.initialized),this.initialized)return void console.log("Activity tree already initialized, skipping");if(this.container=document.getElementById("activity-tree-container"),!this.container&&(this.container=document.getElementById("activity-tree"),!this.container))return void console.error("Activity tree container not found in DOM");this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing existing text content from container:",this.container.textContent),this.container.textContent=""),console.log("Activity tree container found:",this.container);const t=document.getElementById("activity-tab");if(t){if(!t.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.container.textContent&&this.container.textContent.trim()&&(this.container.textContent=""),this.setupControls(),this.initializeTreeData(),this.subscribeToEvents(),void(this.initialized=!0);if(this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing container text before creating visualization"),this.container.textContent=""),this.setupControls(),this.createVisualization(),!this.svg||!this.treeGroup)return console.error("Failed to create D3 visualization elements"),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ Failed to create visualization. Please refresh the page.</div>'));this.initializeTreeData(),this.root?this.update(this.root):console.warn("Root not created, skipping initial update"),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}forceShow(){if(console.log("ActivityTree.forceShow() called"),this.container||(this.container=document.getElementById("activity-tree-container")||document.getElementById("activity-tree"),this.container)){if(this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing text from container:",this.container.textContent),this.container.innerHTML=""),this.svg||this.createVisualization(),this.root||this.initializeTreeData(),this.root&&this.svg&&this.treeGroup&&this.update(this.root),this.svg){const t=this.svg.node();t&&(t.style.display="block",t.style.visibility="visible")}}else console.error("Cannot find activity tree container")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),this.container&&this.container.textContent&&this.container.textContent.trim()&&!this.svg&&(console.log("Clearing text content before rendering:",this.container.textContent),this.container.textContent=""),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.svg||(console.log("Creating deferred visualization..."),this.createVisualization(),this.svg&&this.treeGroup&&this.root?this.update(this.root):this.root||(console.warn("No root node available, initializing tree data..."),this.initializeTreeData(),this.root&&this.svg&&this.treeGroup&&this.update(this.root))),this.root&&this.svg?(console.log("Updating tree with current data..."),this.update(this.root)):console.warn("Cannot update tree - missing components:",{hasRoot:!!this.root,hasSvg:!!this.svg,hasTreeGroup:!!this.treeGroup})}setupControls(){const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAll());const e=document.getElementById("collapse-all");e&&e.addEventListener("click",()=>this.collapseAll());const i=document.getElementById("reset-zoom");i&&i.addEventListener("click",()=>this.resetZoom());const o=document.getElementById("time-range");o&&o.addEventListener("change",t=>{this.timeRange=t.target.value,this.filterEventsByTime()});const n=document.getElementById("activity-search");n&&n.addEventListener("input",t=>{this.searchTerm=t.target.value.toLowerCase(),this.highlightSearchResults()})}createVisualization(){if("undefined"==typeof d3)return console.error("D3.js is not loaded! Cannot create activity tree visualization."),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ D3.js is not loaded. Cannot create visualization.</div>'));const t=this.container.getBoundingClientRect();this.width=t.width-this.margin.left-this.margin.right,this.height=Math.max(500,t.height-this.margin.top-this.margin.bottom),console.log("Creating D3 visualization with dimensions:",{width:this.width,height:this.height}),d3.select(this.container).selectAll("*").remove(),this.svg=d3.select(this.container).append("svg").attr("width","100%").attr("height","100%").attr("viewBox",`0 0 ${this.width+this.margin.left+this.margin.right} ${this.height+this.margin.top+this.margin.bottom}`),this.treeGroup=this.svg.append("g").attr("class","tree-group").attr("transform",`translate(${this.margin.left},${this.margin.top})`);const e=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.call(e),this.treeLayout=d3.tree().size([this.height,this.width]),console.log("ActivityTree: Tree layout created:",this.treeLayout),this.tooltip=d3.select("body").append("div").attr("class","activity-tooltip").style("opacity",0),console.log("ActivityTree: Visualization complete, svg:",this.svg,"treeGroup:",this.treeGroup)}initializeTreeData(){if(console.log("ActivityTree: Initializing tree data"),this.treeData={name:"PM",type:"pm",icon:"🎯",children:[],_children:null},"undefined"==typeof d3)return console.error("ActivityTree: D3 is not available - cannot create hierarchy!"),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ Waiting for D3.js to load...</div>'));this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,console.log("ActivityTree: Root node created:",this.root),this.updateStats()}subscribeToEvents(){if(!window.socketClient)return console.warn("Socket client not available for activity tree"),void setTimeout(()=>this.subscribeToEvents(),1e3);console.log("ActivityTree: Setting up event subscription"),window.socketClient.onEventUpdate(t=>{console.log(`ActivityTree: onEventUpdate called with ${t.length} total events`);const e=t.length-this.events.length;if(e>0){const i=t.slice(this.events.length);console.log(`ActivityTree: Processing ${e} new events`,i),i.forEach(t=>{this.processEvent(t)}),this.events=[...t]}});const t=window.socketClient?.events||window.eventViewer?.events||[];t.length>0?(console.log(`ActivityTree: Processing ${t.length} existing events`,t),t.forEach(t=>{this.processEvent(t)}),this.events=[...t]):(console.log("ActivityTree: No existing events found"),this.events=[])}processEvent(t){if(!t)return void console.log("ActivityTree: Ignoring null event");let e=null;if(t.hook_event_name)e=t.hook_event_name;else if("hook"===t.type&&t.subtype){e={pre_tool:"PreToolUse",post_tool:"PostToolUse",subagent_start:"SubagentStart",subagent_stop:"SubagentStop",todo_write:"TodoWrite"}[t.subtype]}else"todo"===t.type&&"updated"===t.subtype?e="TodoWrite":"subagent"===t.type?"started"===t.subtype?e="SubagentStart":"stopped"===t.subtype&&(e="SubagentStop"):"start"===t.type&&(e="Start");if(!e)return void("hook"!==t.type&&"todo"!==t.type&&"subagent"!==t.type||console.log("ActivityTree: Cannot determine event type for:",t));console.log(`ActivityTree: Processing event: ${e}`,t);const i=new Date(t.timestamp);if(this.isEventInTimeRange(i)){switch(e){case"TodoWrite":this.processTodoWrite(t);break;case"SubagentStart":this.processSubagentStart(t);break;case"SubagentStop":this.processSubagentStop(t);break;case"PreToolUse":this.processToolUse(t);break;case"PostToolUse":this.updateToolStatus(t,"completed");break;case"Start":this.initializeTreeData(),this.update(this.root)}this.updateStats()}}processTodoWrite(t){console.log("ActivityTree: Processing TodoWrite event:",t);let e=t.todos||t.data?.todos||t.data||[];if(e&&"object"==typeof e&&e.todos&&(e=e.todos),!Array.isArray(e))return void console.log("ActivityTree: Invalid todos format in event:",t);if(0===e.length)return void console.log("ActivityTree: No todos in event");const i=e.find(t=>"in_progress"===t.status);if(!i)return void console.log("ActivityTree: No in-progress todo found");console.log("ActivityTree: Found active todo:",i);const o={name:i.activeForm||i.content,type:"todowrite",icon:"📝",content:i.content,status:i.status,timestamp:t.timestamp,children:[],_children:null,eventId:t.id};this.root?this.root.data?(this.root.data.children||(this.root.data.children=[]),console.log("ActivityTree: Adding TodoWrite node to root"),this.root.data.children.push(o),this.todoWriteStack.push({node:o,content:i.content}),console.log("ActivityTree: Calling update with root:",this.root),this.update(this.root),console.log("ActivityTree: Update complete")):console.error("ActivityTree: Root has no data!"):console.error("ActivityTree: No root node!")}processSubagentStart(t){const e=t.agent_name||t.data?.agent_name||t.data?.agent_type||t.agent_type||t.agent||"unknown",i={name:e,type:"agent",icon:this.getAgentIcon(e),timestamp:t.timestamp,children:[],_children:null,eventId:t.id,sessionId:t.session_id||t.data?.session_id};let o=null;if(this.todoWriteStack.length>0){const t=this.todoWriteStack[this.todoWriteStack.length-1];t.content&&t.content.toLowerCase().includes(e.toLowerCase())&&(o=t.node)}o||(o=this.root.data),o.children||(o.children=[]),o.children.push(i),this.activeAgent=i,this.activeAgentStack.push(i),this.update(this.root)}processSubagentStop(t){const e=t.session_id||t.data?.session_id;this.activeAgent&&this.activeAgent.sessionId===e&&(this.activeAgent.status="completed",this.activeAgentStack.pop(),this.activeAgent=this.activeAgentStack.length>0?this.activeAgentStack[this.activeAgentStack.length-1]:null),this.update(this.root)}processToolUse(t){const e=t.tool_name||t.data?.tool_name||t.tool||t.data?.tool||"unknown",i=this.getToolIcon(e),o=t.tool_parameters||t.data?.tool_parameters||t.parameters||t.data?.parameters||{},n={name:e,type:"tool",icon:i,timestamp:t.timestamp,status:"in_progress",children:[],_children:null,eventId:t.id};"Read"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"📄",timestamp:t.timestamp}):"Edit"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"✏️",timestamp:t.timestamp}):"Write"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"💾",timestamp:t.timestamp}):"Bash"===e&&o.command?n.children.push({name:o.command.substring(0,50)+(o.command.length>50?"...":""),type:"command",icon:"⚡",timestamp:t.timestamp}):"WebFetch"===e&&o.url&&n.children.push({name:o.url,type:"url",icon:"🌐",timestamp:t.timestamp});let s=this.activeAgent||this.root.data;s.children||(s.children=[]),s.children.push(n),this.update(this.root)}updateToolStatus(t,e){const i=o=>{if(o.eventId===t.id)return o.status=e,!0;if(o.children)for(let t of o.children)if(i(t))return!0;if(o._children)for(let t of o._children)if(i(t))return!0;return!1};i(this.root.data),this.update(this.root)}getAgentIcon(t){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️"}[t.toLowerCase()]||"🤖"}getToolIcon(t){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[t.toLowerCase()]||"🔧"}update(t){if(console.log("ActivityTree: update() called with source:",t),"undefined"==typeof d3)return void console.error("ActivityTree: Cannot update - D3.js not loaded");if(!this.svg||!this.treeGroup){if(console.warn("ActivityTree: Cannot update - SVG not initialized"),!this.container)return;if(console.log("Attempting to create visualization from update()"),this.createVisualization(),!this.svg||!this.treeGroup)return void console.error("Failed to create visualization in update()")}if(!this.treeLayout){if(console.warn("ActivityTree: Cannot update - tree layout not initialized"),"undefined"==typeof d3)return;this.treeLayout=d3.tree().size([this.height,this.width]),console.log("Created tree layout in update()")}if(!t||!t.data)return void console.error("ActivityTree: Invalid source in update()",t);if(!this.root)return void console.error("ActivityTree: No root node available for update");let e;try{e=this.treeLayout(this.root)}catch(c){return void console.error("ActivityTree: Error computing tree layout:",c)}const i=e.descendants(),o=e.links();if(console.log(`ActivityTree: Updating tree with ${i.length} nodes`),1===i.length&&this.container){this.container.querySelector("svg")||console.warn("SVG element not found in container after update")}i.forEach(t=>{t.y=180*t.depth});const n=this.treeGroup.selectAll("g.node").data(i,t=>t.id||(t.id=++this.nodeId)),s=n.enter().append("g").attr("class","node").attr("transform",e=>`translate(${t.y0},${t.x0})`).on("click",(t,e)=>this.click(e));s.append("circle").attr("class",t=>`node-circle ${t.data.type}`).attr("r",1e-6).style("fill",t=>t._children?this.getNodeColor(t.data.type):"#fff").style("stroke",t=>this.getNodeColor(t.data.type)),s.append("text").attr("class","node-icon").attr("dy",".35em").attr("text-anchor","middle").style("font-size","14px").text(t=>t.data.icon||""),s.append("text").attr("class","node-label").attr("dy",".35em").attr("x",t=>t.children||t._children?-25:25).attr("text-anchor",t=>t.children||t._children?"end":"start").text(t=>t.data.name).style("fill-opacity",1e-6),s.on("mouseover",(t,e)=>this.showTooltip(t,e)).on("mouseout",()=>this.hideTooltip());const r=s.merge(n);r.transition().duration(this.duration).attr("transform",t=>`translate(${t.y},${t.x})`),r.select("circle.node-circle").attr("r",10).style("fill",t=>"in_progress"===t.data.status||t._children?this.getNodeColor(t.data.type):"#fff").attr("class",t=>{let e=`node-circle ${t.data.type}`;return"in_progress"===t.data.status&&(e+=" pulsing"),"failed"===t.data.status&&(e+=" failed"),e}),r.select("text.node-label").style("fill-opacity",1);const a=n.exit().transition().duration(this.duration).attr("transform",e=>`translate(${t.y},${t.x})`).remove();a.select("circle").attr("r",1e-6),a.select("text").style("fill-opacity",1e-6);const l=this.treeGroup.selectAll("path.link").data(o,t=>t.target.id);l.enter().insert("path","g").attr("class","link").attr("d",e=>{const i={x:t.x0,y:t.y0};return this.diagonal({source:i,target:i})}).merge(l).transition().duration(this.duration).attr("d",this.diagonal),l.exit().transition().duration(this.duration).attr("d",e=>{const i={x:t.x,y:t.y};return this.diagonal({source:i,target:i})}).remove(),i.forEach(t=>{t.x0=t.x,t.y0=t.y}),this.updateBreadcrumb(t)}diagonal(t){return`M ${t.source.y} ${t.source.x}\n C ${(t.source.y+t.target.y)/2} ${t.source.x},\n ${(t.source.y+t.target.y)/2} ${t.target.x},\n ${t.target.y} ${t.target.x}`}click(t){t.children?(t._children=t.children,t.children=null):(t.children=t._children,t._children=null),this.update(t),this.updateBreadcrumb(t)}getNodeColor(t){return{pm:"#4299e1",todowrite:"#48bb78",agent:"#ed8936",tool:"#9f7aea",file:"#38b2ac",command:"#f56565",url:"#4299e1"}[t]||"#718096"}showTooltip(t,e){const i=`\n <strong>${e.data.name}</strong><br>\n Type: ${e.data.type}<br>\n ${e.data.timestamp?`Time: ${new Date(e.data.timestamp).toLocaleTimeString()}`:""}\n ${e.data.status?`<br>Status: ${e.data.status}`:""}\n `;this.tooltip.transition().duration(200).style("opacity",.9),this.tooltip.html(i).style("left",t.pageX+10+"px").style("top",t.pageY-28+"px")}hideTooltip(){this.tooltip.transition().duration(500).style("opacity",0)}expandAll(){const t=e=>{e._children&&(e.children=e._children,e._children=null),e.children&&e.children.forEach(t)};t(this.root),this.update(this.root)}collapseAll(){const t=e=>{e.children&&(e._children=e.children,e._children.forEach(t),e.children=null)};this.root.children?.forEach(t),this.update(this.root)}resetZoom(){if(!this.svg)return void console.warn("Cannot reset zoom: SVG not initialized");const t=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.transition().duration(750).call(t.transform,d3.zoomIdentity),this.treeGroup.transition().duration(750).attr("transform",`translate(${this.margin.left},${this.margin.top})`)}isEventInTimeRange(t){if("all"===this.timeRange)return!0;const e=(new Date-t)/6e4;switch(this.timeRange){case"10min":return e<=10;case"30min":return e<=30;case"hour":return e<=60;default:return!0}}filterEventsByTime(){this.initializeTreeData(),window.eventViewer&&window.eventViewer.events&&window.eventViewer.events.forEach(t=>{this.processEvent(t)})}updateStats(){if(!this.root||!this.root.data){console.warn("ActivityTree: Cannot update stats - root not initialized");const t=document.getElementById("node-count"),e=document.getElementById("active-count"),i=document.getElementById("tree-depth");return t&&(t.textContent="1"),e&&(e.textContent="0"),void(i&&(i.textContent="0"))}const t=this.countNodes(this.root),e=this.countActiveNodes(this.root.data),i=this.getTreeDepth(this.root),o=document.getElementById("node-count"),n=document.getElementById("active-count"),s=document.getElementById("tree-depth");o&&(o.textContent=t),n&&(n.textContent=e),s&&(s.textContent=i),console.log(`ActivityTree: Stats updated - Nodes: ${t}, Active: ${e}, Depth: ${i}`)}countNodes(t){let e=1;return t.children&&t.children.forEach(t=>{e+=this.countNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countNodes(t)}),e}countActiveNodes(t){let e="in_progress"===t.status?1:0;return t.children&&t.children.forEach(t=>{e+=this.countActiveNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countActiveNodes(t)}),e}getTreeDepth(t){if(!t.children&&!t._children)return 0;const e=(t.children||t._children).map(t=>this.getTreeDepth(t));return Math.max(...e)+1}updateBreadcrumb(t){const e=[];let i=t;for(;i;)e.unshift(i.data.name),i=i.parent;const o=document.getElementById("activity-breadcrumb");o&&(o.textContent=e.join(" > "))}highlightSearchResults(){this.treeGroup.selectAll(".node-label").style("font-weight","normal").style("fill","#2d3748"),this.searchTerm&&this.treeGroup.selectAll(".node-label").style("font-weight",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"bold":"normal").style("fill",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"#e53e3e":"#2d3748")}}window.ActivityTree=t;const e=()=>{let e=null;const i=()=>{e||(console.log("Creating new Activity Tree instance..."),e=new t,window.activityTreeInstance=e);const i=document.getElementById("activity-tree-container")||document.getElementById("activity-tree");i&&i.textContent&&i.textContent.trim()&&(console.log("Clearing text from activity tree container before init:",i.textContent),i.textContent=""),setTimeout(()=>{console.log("Attempting to initialize Activity Tree visualization..."),e.initialize()},100)};document.querySelectorAll(".tab-button").forEach(t=>{t.addEventListener("click",t=>{"activity"===t.target.getAttribute("data-tab")&&(console.log("Activity tab button clicked, initializing tree..."),i(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))})}),document.addEventListener("tabChanged",t=>{t.detail&&"activity"===t.detail.newTab&&(console.log("Tab changed to activity, initializing tree..."),i(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))});const o=document.querySelector(".tab-button.active");o&&"activity"===o.getAttribute("data-tab")&&(console.log("Activity tab is active on load, initializing tree..."),i());const n=document.getElementById("activity-tab");n&&n.classList.contains("active")&&(console.log("Activity panel is active on load, initializing tree..."),e||i()),window.activityTree=()=>e};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e();
|
|
2
|
+
//# sourceMappingURL=activity-tree.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
class e{constructor(e){this.eventViewer=e,this.state={currentDelegation:null,sessionAgents:new Map,eventAgentMap:new Map,pmDelegations:new Map,agentToDelegation:new Map},console.log("Agent inference system initialized")}initialize(){this.state={currentDelegation:null,sessionAgents:new Map,eventAgentMap:new Map,pmDelegations:new Map,agentToDelegation:new Map}}inferAgentFromEvent(e){const t=e.data||{},n=e.session_id||t.session_id||"unknown",a=e.hook_event_name||t.hook_event_name||e.type||"",s=e.subtype||t.subtype||"",i=e.tool_name||t.tool_name||"";if(Math.random()<.1&&console.log("Agent inference debug:",{eventType:a,toolName:i,hasData:!!e.data,dataKeys:Object.keys(t),eventKeys:Object.keys(e),agentType:e.agent_type||t.agent_type,subagentType:e.subagent_type||t.subagent_type}),"SubagentStop"===a||"subagent_stop"===s){const i=this.extractAgentNameFromEvent(e);return console.log("SubagentStop event detected:",{agentName:i,sessionId:n,eventType:a,subtype:s,rawAgentType:e.agent_type||t.agent_type}),{type:"subagent",confidence:"definitive",agentName:i,reason:"SubagentStop event"}}if("Stop"===a||"stop"===s)return{type:"main_agent",confidence:"definitive",agentName:"PM",reason:"Stop event"};if("Task"===i){const t=this.extractSubagentTypeFromTask(e);if(t)return console.log("Task delegation detected:",{agentName:t,sessionId:n,eventType:a}),{type:"subagent",confidence:"high",agentName:t,reason:"Task tool with subagent_type"}}if("PreToolUse"===a&&"Task"===i){const t=this.extractSubagentTypeFromTask(e);if(t)return{type:"subagent",confidence:"high",agentName:t,reason:"PreToolUse Task delegation"}}{const e=n.toLowerCase();if(["subagent","task","agent-"].some(t=>e.includes(t)))return{type:"subagent",confidence:"medium",agentName:"Subagent",reason:"Session ID pattern"}}const o=e.agent_type||t.agent_type||e.agent_id||t.agent_id,g=e.subagent_type||t.subagent_type;if(g&&"unknown"!==g)return{type:"subagent",confidence:"high",agentName:this.normalizeAgentName(g),reason:"subagent_type field"};if(o&&"unknown"!==o&&"main"!==o)return{type:"subagent",confidence:"medium",agentName:this.normalizeAgentName(o),reason:"agent_type field"};if(t.delegation_details?.agent_type)return{type:"subagent",confidence:"high",agentName:this.normalizeAgentName(t.delegation_details.agent_type),reason:"delegation_details"};if(e.type&&e.type.startsWith("hook.")){const a=e.type.replace("hook.","");if("subagent_start"===a||"SubagentStart"===t.hook_event_name){const e=t.agent_type||t.agent_id||"Subagent";return console.log("SubagentStart event from Socket.IO:",{agentName:e,sessionId:n,hookType:a}),{type:"subagent",confidence:"definitive",agentName:this.normalizeAgentName(e),reason:"Socket.IO hook SubagentStart"}}if("subagent_stop"===a||"SubagentStop"===t.hook_event_name){const e=t.agent_type||t.agent_id||"Subagent";return{type:"subagent",confidence:"high",agentName:this.normalizeAgentName(e),reason:"Socket.IO hook SubagentStop"}}}return{type:"main_agent",confidence:"default",agentName:"PM",reason:"default classification"}}normalizeAgentName(e){if(!e)return"Unknown";const t={engineer:"Engineer Agent",research:"Research Agent",qa:"QA Agent",documentation:"Documentation Agent",security:"Security Agent",ops:"Ops Agent",version_control:"Version Control Agent",data_engineer:"Data Engineer Agent",test_integration:"Test Integration Agent",pm:"PM Agent"}[e.toLowerCase()];if(t)return t;let n=e.replace(/_/g," ").split(" ").map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(" ");return n.toLowerCase().includes("agent")||(n+=" Agent"),n}extractSubagentTypeFromTask(e){let t=null;return e.tool_parameters?.subagent_type?t=e.tool_parameters.subagent_type:e.data?.tool_parameters?.subagent_type?t=e.data.tool_parameters.subagent_type:e.data?.delegation_details?.agent_type?t=e.data.delegation_details.agent_type:e.tool_input?.subagent_type&&(t=e.tool_input.subagent_type),t?this.normalizeAgentName(t):null}extractAgentNameFromEvent(e){const t=e.data||{};if("Task"===e.tool_name||"Task"===t.tool_name){const t=this.extractSubagentTypeFromTask(e);if(t)return t}return e.subagent_type&&"unknown"!==e.subagent_type?this.normalizeAgentName(e.subagent_type):t.subagent_type&&"unknown"!==t.subagent_type?this.normalizeAgentName(t.subagent_type):t.delegation_details?.agent_type&&"unknown"!==t.delegation_details.agent_type?this.normalizeAgentName(t.delegation_details.agent_type):e.agent_type&&!["main","unknown"].includes(e.agent_type)?this.normalizeAgentName(e.agent_type):t.agent_type&&!["main","unknown"].includes(t.agent_type)?this.normalizeAgentName(t.agent_type):e.agent_id&&!["main","unknown"].includes(e.agent_id)?this.normalizeAgentName(e.agent_id):t.agent_id&&!["main","unknown"].includes(t.agent_id)?this.normalizeAgentName(t.agent_id):e.agent&&"unknown"!==e.agent?this.normalizeAgentName(e.agent):e.name&&"unknown"!==e.name?this.normalizeAgentName(e.name):"Unknown"}processAgentInference(){const e=this.eventViewer.events;this.state.currentDelegation=null,this.state.sessionAgents.clear(),this.state.eventAgentMap.clear(),this.state.pmDelegations.clear(),this.state.agentToDelegation.clear(),console.log("Processing agent inference for",e.length,"events"),e&&0!==e.length?(e.forEach((e,t)=>{let n;try{const a=this.inferAgentFromEvent(e),s=e.session_id||e.data?.session_id||"default";if(n=a,this.state.currentDelegation&&"default"===a.confidence&&s===this.state.currentDelegation.sessionId&&(n={type:"subagent",confidence:"inherited",agentName:this.state.currentDelegation.agentName,reason:"inherited from delegation context"}),"Task"===e.tool_name&&"subagent"===a.type){const n=`pm_${s}_${t}_${a.agentName}`,i={id:n,agentName:a.agentName,sessionId:s,startIndex:t,endIndex:null,pmCall:e,timestamp:e.timestamp,agentEvents:[]};this.state.pmDelegations.set(n,i),this.state.agentToDelegation.set(a.agentName,n),this.state.currentDelegation={agentName:a.agentName,sessionId:s,startIndex:t,endIndex:null,delegationId:n},console.log("Delegation started:",this.state.currentDelegation)}else if("definitive"===a.confidence&&"SubagentStop event"===a.reason&&this.state.currentDelegation){this.state.currentDelegation.endIndex=t;const e=this.state.pmDelegations.get(this.state.currentDelegation.delegationId);e&&(e.endIndex=t),console.log("Delegation ended:",this.state.currentDelegation),this.state.currentDelegation=null}if(this.state.currentDelegation&&"subagent"===n.type){const a=this.state.pmDelegations.get(this.state.currentDelegation.delegationId);a&&a.agentEvents.push({eventIndex:t,event:e,inference:n})}this.state.eventAgentMap.set(t,n),this.state.sessionAgents.set(s,n),t<5&&console.log(`Event ${t} agent inference:`,{event_type:e.type||e.hook_event_name,subtype:e.subtype,tool_name:e.tool_name,inference:n,hasData:!!e.data,agentType:e.agent_type||e.data?.agent_type})}catch(a){console.error(`Error processing event ${t} for agent inference:`,a),n||(n={type:"main_agent",confidence:"error",agentName:"PM",reason:"error during processing"}),this.state.eventAgentMap.set(t,n)}}),console.log("Agent inference processing complete. Results:",{total_events:e.length,inferred_agents:this.state.eventAgentMap.size,unique_sessions:this.state.sessionAgents.size,pm_delegations:this.state.pmDelegations.size,agent_to_delegation_mappings:this.state.agentToDelegation.size})):console.log("No events to process for agent inference")}getInferredAgent(e){return this.state.eventAgentMap.get(e)||null}getInferredAgentForEvent(e){const t=this.eventViewer.events;let n=t.indexOf(e);if(-1===n&&e.timestamp&&(n=t.findIndex(t=>t.timestamp===e.timestamp&&t.session_id===e.session_id)),-1===n)return console.log("Agent inference: Could not find event in events array, performing inline inference"),this.inferAgentFromEvent(e);let a=this.getInferredAgent(n);return a||(a=this.inferAgentFromEvent(e),this.state.eventAgentMap.set(n,a)),a}getCurrentDelegation(){return this.state.currentDelegation}getSessionAgents(){return this.state.sessionAgents}getEventAgentMap(){return this.state.eventAgentMap}getPMDelegations(){return this.state.pmDelegations}getAgentToDelegationMap(){return this.state.agentToDelegation}getUniqueAgentInstances(){const e=new Map;for(const[a,s]of this.state.pmDelegations){const t=s.agentName;e.has(t)||e.set(t,{id:`consolidated_${t}`,type:"consolidated_agent",agentName:t,delegations:[],pmCalls:[],allEvents:[],firstTimestamp:s.timestamp,lastTimestamp:s.timestamp,totalEventCount:s.agentEvents.length,delegationCount:1});const n=e.get(t);n.delegations.push({id:a,pmCall:s.pmCall,timestamp:s.timestamp,eventCount:s.agentEvents.length,startIndex:s.startIndex,endIndex:s.endIndex,events:s.agentEvents}),s.pmCall&&n.pmCalls.push(s.pmCall),n.allEvents=n.allEvents.concat(s.agentEvents),new Date(s.timestamp)<new Date(n.firstTimestamp)&&(n.firstTimestamp=s.timestamp),new Date(s.timestamp)>new Date(n.lastTimestamp)&&(n.lastTimestamp=s.timestamp),n.totalEventCount+=s.agentEvents.length,n.delegationCount++}const t=this.eventViewer.events;for(let a=0;a<t.length;a++){const n=this.getInferredAgent(a);n&&"subagent"===n.type&&!e.has(n.agentName)&&e.set(n.agentName,{id:`consolidated_${n.agentName}`,type:"consolidated_agent",agentName:n.agentName,delegations:[{id:`implied_pm_${n.agentName}_${a}`,pmCall:null,timestamp:t[a].timestamp,eventCount:1,startIndex:a,endIndex:null,events:[{eventIndex:a,event:t[a],inference:n}]}],pmCalls:[],allEvents:[{eventIndex:a,event:t[a],inference:n}],firstTimestamp:t[a].timestamp,lastTimestamp:t[a].timestamp,totalEventCount:1,delegationCount:1,isImplied:!0})}const n=Array.from(e.values()).sort((e,t)=>new Date(e.firstTimestamp)-new Date(t.firstTimestamp));return console.log("Consolidated unique agents:",{total_unique_agents:n.length,agents:n.map(e=>({name:e.agentName,delegations:e.delegationCount,totalEvents:e.totalEventCount}))}),n}}export{e as A};
|
|
1
|
+
class e{constructor(e){this.eventViewer=e,this.state={currentDelegation:null,sessionAgents:new Map,eventAgentMap:new Map,pmDelegations:new Map,agentToDelegation:new Map,orphanSubagents:new Map,subagentStartEvents:new Map},console.log("Agent inference system initialized")}initialize(){this.state={currentDelegation:null,sessionAgents:new Map,eventAgentMap:new Map,pmDelegations:new Map,agentToDelegation:new Map,orphanSubagents:new Map,subagentStartEvents:new Map}}inferAgentFromEvent(e){const t=e.data||{},n=e.session_id||t.session_id||"unknown",a=e.hook_event_name||t.hook_event_name||e.type||"",s=e.subtype||t.subtype||"",i=e.tool_name||t.tool_name||"";if(Math.random()<.1&&console.log("Agent inference debug:",{eventType:a,toolName:i,hasData:!!e.data,dataKeys:Object.keys(t),eventKeys:Object.keys(e),agentType:e.agent_type||t.agent_type,subagentType:e.subagent_type||t.subagent_type}),"SubagentStop"===a||"subagent_stop"===s){const i=this.extractAgentNameFromEvent(e);return console.log("SubagentStop event detected:",{agentName:i,sessionId:n,eventType:a,subtype:s,rawAgentType:e.agent_type||t.agent_type}),{type:"subagent",confidence:"definitive",agentName:i,reason:"SubagentStop event"}}if("Stop"===a||"stop"===s)return{type:"main_agent",confidence:"definitive",agentName:"PM",reason:"Stop event"};if("Task"===i){const t=this.extractSubagentTypeFromTask(e);if(t)return console.log("Task delegation detected:",{agentName:t,sessionId:n,eventType:a}),{type:"subagent",confidence:"high",agentName:t,reason:"Task tool with subagent_type"}}if("PreToolUse"===a&&"Task"===i){const t=this.extractSubagentTypeFromTask(e);if(t)return{type:"subagent",confidence:"high",agentName:t,reason:"PreToolUse Task delegation"}}{const e=n.toLowerCase();if(["subagent","task","agent-"].some(t=>e.includes(t)))return{type:"subagent",confidence:"medium",agentName:"Subagent",reason:"Session ID pattern"}}const o=e.agent_type||t.agent_type||e.agent_id||t.agent_id,g=e.subagent_type||t.subagent_type;if(g&&"unknown"!==g)return{type:"subagent",confidence:"high",agentName:this.normalizeAgentName(g),reason:"subagent_type field"};if(o&&"unknown"!==o&&"main"!==o)return{type:"subagent",confidence:"medium",agentName:this.normalizeAgentName(o),reason:"agent_type field"};if(t.delegation_details?.agent_type)return{type:"subagent",confidence:"high",agentName:this.normalizeAgentName(t.delegation_details.agent_type),reason:"delegation_details"};if(e.type&&e.type.startsWith("hook.")){const a=e.type.replace("hook.","");if("subagent_start"===a||"SubagentStart"===t.hook_event_name){const e=t.agent_type||t.agent_id||"Subagent";return console.log("SubagentStart event from Socket.IO:",{agentName:e,sessionId:n,hookType:a}),{type:"subagent",confidence:"definitive",agentName:this.normalizeAgentName(e),reason:"Socket.IO hook SubagentStart"}}if("subagent_stop"===a||"SubagentStop"===t.hook_event_name){const e=t.agent_type||t.agent_id||"Subagent";return{type:"subagent",confidence:"high",agentName:this.normalizeAgentName(e),reason:"Socket.IO hook SubagentStop"}}}return{type:"main_agent",confidence:"default",agentName:"PM",reason:"default classification"}}normalizeAgentName(e){if(!e)return"Unknown";const t={engineer:"Engineer Agent",research:"Research Agent",qa:"QA Agent",documentation:"Documentation Agent",security:"Security Agent",ops:"Ops Agent",version_control:"Version Control Agent",data_engineer:"Data Engineer Agent",test_integration:"Test Integration Agent",pm:"PM Agent"}[e.toLowerCase()];if(t)return t;let n=e.replace(/_/g," ").split(" ").map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(" ");return n.toLowerCase().includes("agent")||(n+=" Agent"),n}extractSubagentTypeFromTask(e){let t=null;return e.tool_parameters?.subagent_type?t=e.tool_parameters.subagent_type:e.data?.tool_parameters?.subagent_type?t=e.data.tool_parameters.subagent_type:e.data?.delegation_details?.agent_type?t=e.data.delegation_details.agent_type:e.tool_input?.subagent_type&&(t=e.tool_input.subagent_type),t?this.normalizeAgentName(t):null}extractAgentNameFromEvent(e){const t=e.data||{};if("Task"===e.tool_name||"Task"===t.tool_name){const t=this.extractSubagentTypeFromTask(e);if(t)return t}return e.subagent_type&&"unknown"!==e.subagent_type?this.normalizeAgentName(e.subagent_type):t.subagent_type&&"unknown"!==t.subagent_type?this.normalizeAgentName(t.subagent_type):t.delegation_details?.agent_type&&"unknown"!==t.delegation_details.agent_type?this.normalizeAgentName(t.delegation_details.agent_type):e.agent_type&&!["main","unknown"].includes(e.agent_type)?this.normalizeAgentName(e.agent_type):t.agent_type&&!["main","unknown"].includes(t.agent_type)?this.normalizeAgentName(t.agent_type):e.agent_id&&!["main","unknown"].includes(e.agent_id)?this.normalizeAgentName(e.agent_id):t.agent_id&&!["main","unknown"].includes(t.agent_id)?this.normalizeAgentName(t.agent_id):e.agent&&"unknown"!==e.agent?this.normalizeAgentName(e.agent):e.name&&"unknown"!==e.name?this.normalizeAgentName(e.name):"Unknown"}processAgentInference(){const e=this.eventViewer.events;this.state.currentDelegation=null,this.state.sessionAgents.clear(),this.state.eventAgentMap.clear(),this.state.pmDelegations.clear(),this.state.agentToDelegation.clear(),this.state.orphanSubagents.clear(),this.state.subagentStartEvents.clear(),console.log("Processing agent inference for",e.length,"events"),e&&0!==e.length?(e.forEach((e,t)=>{let n;try{const a=this.inferAgentFromEvent(e),s=e.session_id||e.data?.session_id||"default";n=a,this.state.currentDelegation&&"default"===a.confidence&&s===this.state.currentDelegation.sessionId&&(n={type:"subagent",confidence:"inherited",agentName:this.state.currentDelegation.agentName,reason:"inherited from delegation context"});const i=e.hook_event_name||e.data?.hook_event_name||"";if(("SubagentStart"===i||"hook.subagent_start"===e.type||"subagent_start"===e.subtype)&&"subagent"===a.type&&(this.state.subagentStartEvents.has(a.agentName)||this.state.subagentStartEvents.set(a.agentName,[]),this.state.subagentStartEvents.get(a.agentName).push({eventIndex:t,event:e,timestamp:e.timestamp,sessionId:s})),"Task"===e.tool_name&&"subagent"===a.type){const n=`pm_${s}_${t}_${a.agentName}`,i={id:n,agentName:a.agentName,sessionId:s,startIndex:t,endIndex:null,pmCall:e,timestamp:e.timestamp,agentEvents:[]};this.state.pmDelegations.set(n,i),this.state.agentToDelegation.set(a.agentName,n),this.state.currentDelegation={agentName:a.agentName,sessionId:s,startIndex:t,endIndex:null,delegationId:n},console.log("Delegation started:",this.state.currentDelegation)}else if("definitive"===a.confidence&&"SubagentStop event"===a.reason&&this.state.currentDelegation){this.state.currentDelegation.endIndex=t;const e=this.state.pmDelegations.get(this.state.currentDelegation.delegationId);e&&(e.endIndex=t),console.log("Delegation ended:",this.state.currentDelegation),this.state.currentDelegation=null}if(this.state.currentDelegation&&"subagent"===n.type){const a=this.state.pmDelegations.get(this.state.currentDelegation.delegationId);a&&a.agentEvents.push({eventIndex:t,event:e,inference:n})}this.state.eventAgentMap.set(t,n),this.state.sessionAgents.set(s,n),t<5&&console.log(`Event ${t} agent inference:`,{event_type:e.type||e.hook_event_name,subtype:e.subtype,tool_name:e.tool_name,inference:n,hasData:!!e.data,agentType:e.agent_type||e.data?.agent_type})}catch(a){console.error(`Error processing event ${t} for agent inference:`,a),n||(n={type:"main_agent",confidence:"error",agentName:"PM",reason:"error during processing"}),this.state.eventAgentMap.set(t,n)}}),this.identifyOrphanSubagents(e),console.log("Agent inference processing complete. Results:",{total_events:e.length,inferred_agents:this.state.eventAgentMap.size,unique_sessions:this.state.sessionAgents.size,pm_delegations:this.state.pmDelegations.size,agent_to_delegation_mappings:this.state.agentToDelegation.size,orphan_subagents:this.state.orphanSubagents.size})):console.log("No events to process for agent inference")}getInferredAgent(e){return this.state.eventAgentMap.get(e)||null}getInferredAgentForEvent(e){const t=this.eventViewer.events;let n=t.indexOf(e);if(-1===n&&e.timestamp&&(n=t.findIndex(t=>t.timestamp===e.timestamp&&t.session_id===e.session_id)),-1===n)return console.log("Agent inference: Could not find event in events array, performing inline inference"),this.inferAgentFromEvent(e);let a=this.getInferredAgent(n);return a||(a=this.inferAgentFromEvent(e),this.state.eventAgentMap.set(n,a)),a}getCurrentDelegation(){return this.state.currentDelegation}getSessionAgents(){return this.state.sessionAgents}getEventAgentMap(){return this.state.eventAgentMap}getPMDelegations(){return this.state.pmDelegations}getAgentToDelegationMap(){return this.state.agentToDelegation}buildDelegationHierarchy(){const e=this.getPMDelegations(),t=this.eventViewer.events,n={mainPM:{type:"pm",name:"PM",delegations:[],ownEvents:[],totalEvents:0},impliedPM:{type:"pm_implied",name:"Implied PM",delegations:[],ownEvents:[],totalEvents:0}};for(const[s,i]of e)n.mainPM.delegations.push({id:s,agentName:i.agentName,taskContext:this.extractTaskContext(i.pmCall),events:i.agentEvents,startTime:i.timestamp,endTime:i.endIndex?t[i.endIndex]?.timestamp:null,status:i.endIndex?"completed":"active"}),n.mainPM.totalEvents+=i.agentEvents.length;t.forEach((e,t)=>{const a=this.getInferredAgent(t);a&&"main_agent"===a.type&&(n.mainPM.ownEvents.push({eventIndex:t,event:e}),n.mainPM.totalEvents++)});const a=new Map;t.forEach((t,n)=>{const s=this.getInferredAgent(n);if(s&&"subagent"===s.type){let i=!0;for(const[t,a]of e)if(a.agentEvents.some(e=>e.eventIndex===n)){i=!1;break}if(i){const e=s.agentName;a.has(e)||a.set(e,[]),a.get(e).push({eventIndex:n,event:t,inference:s})}}});for(const[s,i]of a)n.impliedPM.delegations.push({id:`implied_${s}`,agentName:s,taskContext:"No explicit PM delegation",events:i,startTime:i[0].event.timestamp,endTime:i[i.length-1].event.timestamp,status:"completed"}),n.impliedPM.totalEvents+=i.length;return n}extractTaskContext(e){if(!e)return"Unknown task";const t=e.tool_parameters||e.data?.tool_parameters||{};return t.task||t.request||t.description||"Task delegation"}identifyOrphanSubagents(e){for(const[t,n]of this.state.subagentStartEvents)for(const a of n){const n=a.eventIndex,s=new Date(a.timestamp).getTime();let i=!1;for(let a=Math.max(0,n-20);a<n;a++){const n=e[a];if(!n)continue;const o=s-new Date(n.timestamp).getTime();if("Task"===n.tool_name&&o>=0&&o<1e4){const e=this.state.eventAgentMap.get(a);if(e&&e.agentName===t){i=!0;break}}}i||this.state.orphanSubagents.set(n,{agentName:t,timestamp:a.timestamp,sessionId:a.sessionId,event:a.event,groupingKey:null})}this.groupOrphanSubagents(5e3)}groupOrphanSubagents(e){const t=Array.from(this.state.orphanSubagents.values()).sort((e,t)=>new Date(e.timestamp)-new Date(t.timestamp));let n=null,a=null;for(const s of t){const t=new Date(s.timestamp).getTime();(!n||a&&t-a>e)&&(n=`implied_pm_${s.sessionId}_${t}`),s.groupingKey=n,a=t}}isOrphanSubagent(e){return this.state.orphanSubagents.has(e)}getOrphanContext(e){return this.state.orphanSubagents.get(e)||null}getOrphanGroups(){const e=new Map;for(const t of this.state.orphanSubagents.values()){const n=t.groupingKey;e.has(n)||e.set(n,[]),e.get(n).push(t)}return e}getUniqueAgentInstances(){const e=new Map;for(const[a,s]of this.state.pmDelegations){const t=s.agentName;e.has(t)||e.set(t,{id:`consolidated_${t}`,type:"consolidated_agent",agentName:t,delegations:[],pmCalls:[],allEvents:[],firstTimestamp:s.timestamp,lastTimestamp:s.timestamp,totalEventCount:s.agentEvents.length,delegationCount:1});const n=e.get(t);n.delegations.push({id:a,pmCall:s.pmCall,timestamp:s.timestamp,eventCount:s.agentEvents.length,startIndex:s.startIndex,endIndex:s.endIndex,events:s.agentEvents}),s.pmCall&&n.pmCalls.push(s.pmCall),n.allEvents=n.allEvents.concat(s.agentEvents),new Date(s.timestamp)<new Date(n.firstTimestamp)&&(n.firstTimestamp=s.timestamp),new Date(s.timestamp)>new Date(n.lastTimestamp)&&(n.lastTimestamp=s.timestamp),n.totalEventCount+=s.agentEvents.length,n.delegationCount++}const t=this.eventViewer.events;for(let a=0;a<t.length;a++){const n=this.getInferredAgent(a);n&&"subagent"===n.type&&!e.has(n.agentName)&&e.set(n.agentName,{id:`consolidated_${n.agentName}`,type:"consolidated_agent",agentName:n.agentName,delegations:[{id:`implied_pm_${n.agentName}_${a}`,pmCall:null,timestamp:t[a].timestamp,eventCount:1,startIndex:a,endIndex:null,events:[{eventIndex:a,event:t[a],inference:n}]}],pmCalls:[],allEvents:[{eventIndex:a,event:t[a],inference:n}],firstTimestamp:t[a].timestamp,lastTimestamp:t[a].timestamp,totalEventCount:1,delegationCount:1,isImplied:!0})}const n=Array.from(e.values()).sort((e,t)=>new Date(e.firstTimestamp)-new Date(t.firstTimestamp));return console.log("Consolidated unique agents:",{total_unique_agents:n.length,agents:n.map(e=>({name:e.agentName,delegations:e.delegationCount,totalEvents:e.totalEventCount}))}),n}}export{e as A};
|
|
2
2
|
//# sourceMappingURL=agent-inference.js.map
|