claude-mpm 4.2.44__py3-none-any.whl → 4.2.51__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/BASE_PM.md +43 -1
- claude_mpm/agents/INSTRUCTIONS.md +75 -1
- claude_mpm/agents/WORKFLOW.md +46 -1
- claude_mpm/agents/frontmatter_validator.py +20 -12
- claude_mpm/agents/templates/nextjs_engineer.json +277 -0
- claude_mpm/agents/templates/python_engineer.json +289 -0
- claude_mpm/agents/templates/react_engineer.json +11 -3
- claude_mpm/agents/templates/security.json +50 -9
- claude_mpm/cli/commands/agents.py +2 -2
- claude_mpm/cli/commands/uninstall.py +1 -2
- claude_mpm/cli/interactive/agent_wizard.py +3 -3
- claude_mpm/cli/parsers/agent_manager_parser.py +3 -3
- claude_mpm/cli/parsers/agents_parser.py +1 -1
- claude_mpm/constants.py +1 -1
- claude_mpm/core/error_handler.py +2 -4
- claude_mpm/core/file_utils.py +4 -12
- claude_mpm/core/log_manager.py +8 -5
- claude_mpm/core/logger.py +1 -1
- claude_mpm/core/logging_utils.py +6 -6
- claude_mpm/core/unified_agent_registry.py +18 -4
- claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +188 -0
- claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +156 -0
- claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +38 -0
- claude_mpm/dashboard/react/components/shared/FilterBar.module.css +92 -0
- claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +248 -0
- claude_mpm/dashboard/static/archive/activity_dashboard_test.html +61 -0
- claude_mpm/dashboard/static/archive/test_activity_connection.html +179 -0
- claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +68 -0
- claude_mpm/dashboard/static/archive/test_dashboard.html +409 -0
- claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +519 -0
- claude_mpm/dashboard/static/archive/test_dashboard_verification.html +181 -0
- claude_mpm/dashboard/static/archive/test_file_data.html +315 -0
- claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +243 -0
- claude_mpm/dashboard/static/archive/test_file_tree_fix.html +234 -0
- claude_mpm/dashboard/static/archive/test_file_tree_rename.html +117 -0
- claude_mpm/dashboard/static/archive/test_file_tree_tab.html +115 -0
- claude_mpm/dashboard/static/archive/test_file_viewer.html +224 -0
- claude_mpm/dashboard/static/archive/test_final_activity.html +220 -0
- claude_mpm/dashboard/static/archive/test_tab_fix.html +139 -0
- claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +1 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/built/components/agent-hierarchy.js +777 -0
- claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/built/components/build-tracker.js +333 -0
- claude_mpm/dashboard/static/built/components/code-simple.js +857 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +353 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +235 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +409 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +435 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js +2 -1076
- claude_mpm/dashboard/static/built/components/connection-debug.js +654 -0
- claude_mpm/dashboard/static/built/components/diff-viewer.js +891 -0
- claude_mpm/dashboard/static/built/components/event-processor.js +1 -1
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/export-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/file-change-tracker.js +443 -0
- claude_mpm/dashboard/static/built/components/file-change-viewer.js +690 -0
- 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/nav-bar.js +145 -0
- claude_mpm/dashboard/static/built/components/page-structure.js +429 -0
- claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -465
- claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/built/connection-manager.js +536 -0
- claude_mpm/dashboard/static/built/dashboard.js +1 -1
- claude_mpm/dashboard/static/built/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/built/react/events.js +30 -0
- claude_mpm/dashboard/static/built/shared/dom-helpers.js +396 -0
- claude_mpm/dashboard/static/built/shared/event-bus.js +330 -0
- claude_mpm/dashboard/static/built/shared/event-filter-service.js +540 -0
- claude_mpm/dashboard/static/built/shared/logger.js +385 -0
- claude_mpm/dashboard/static/built/shared/page-structure.js +251 -0
- claude_mpm/dashboard/static/built/shared/tooltip-service.js +253 -0
- claude_mpm/dashboard/static/built/socket-client.js +1 -1
- claude_mpm/dashboard/static/built/tab-isolation-fix.js +185 -0
- claude_mpm/dashboard/static/css/dashboard.css +28 -5
- claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +1 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +1 -1
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/export-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/dist/components/module-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/react/events.js +30 -0
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/events.html +607 -0
- claude_mpm/dashboard/static/index.html +713 -0
- claude_mpm/dashboard/static/js/components/activity-tree.js +3 -17
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +4 -1
- claude_mpm/dashboard/static/js/components/agent-inference.js +3 -0
- claude_mpm/dashboard/static/js/components/build-tracker.js +8 -0
- claude_mpm/dashboard/static/js/components/code-viewer.js +306 -66
- claude_mpm/dashboard/static/js/components/event-processor.js +3 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +39 -2
- claude_mpm/dashboard/static/js/components/export-manager.js +3 -0
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +30 -10
- claude_mpm/dashboard/static/js/components/socket-manager.js +4 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +285 -85
- claude_mpm/dashboard/static/js/components/working-directory.js +3 -0
- claude_mpm/dashboard/static/js/dashboard.js +61 -33
- claude_mpm/dashboard/static/js/socket-client.js +12 -8
- claude_mpm/dashboard/static/js/stores/dashboard-store.js +562 -0
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
- claude_mpm/dashboard/static/legacy/activity.html +736 -0
- claude_mpm/dashboard/static/legacy/agents.html +786 -0
- claude_mpm/dashboard/static/legacy/files.html +747 -0
- claude_mpm/dashboard/static/legacy/tools.html +831 -0
- claude_mpm/dashboard/static/monitors-index.html +218 -0
- claude_mpm/dashboard/static/monitors.html +431 -0
- claude_mpm/dashboard/static/production/events.html +659 -0
- claude_mpm/dashboard/static/production/main.html +715 -0
- claude_mpm/dashboard/static/production/monitors.html +483 -0
- claude_mpm/dashboard/static/socket.io.min.js +7 -0
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +7 -0
- claude_mpm/dashboard/static/test-archive/dashboard.html +635 -0
- claude_mpm/dashboard/static/test-archive/debug-events.html +147 -0
- claude_mpm/dashboard/static/test-archive/test-navigation.html +256 -0
- claude_mpm/dashboard/static/test-archive/test-react-exports.html +180 -0
- claude_mpm/dashboard/templates/index.html +79 -9
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +1 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +25 -8
- claude_mpm/services/agents/deployment/agent_validator.py +3 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +13 -4
- claude_mpm/services/agents/local_template_manager.py +2 -6
- claude_mpm/services/monitor/daemon.py +1 -2
- claude_mpm/services/monitor/daemon_manager.py +2 -5
- claude_mpm/services/monitor/event_emitter.py +2 -2
- claude_mpm/services/monitor/handlers/code_analysis.py +4 -6
- claude_mpm/services/monitor/handlers/hooks.py +2 -4
- claude_mpm/services/monitor/server.py +27 -4
- claude_mpm/tools/code_tree_analyzer.py +2 -2
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/RECORD +146 -81
- claude_mpm/dashboard/static/test-browser-monitor.html +0 -470
- claude_mpm/dashboard/static/test-simple.html +0 -97
- /claude_mpm/dashboard/static/{test_debug.html → test-archive/test_debug.html} +0 -0
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/top_level.txt +0 -0
@@ -150,6 +150,23 @@
|
|
150
150
|
<div class="header-row">
|
151
151
|
<div class="header-title">
|
152
152
|
<h1>🚀 Claude MPM Monitor</h1>
|
153
|
+
<a href="/static/monitors-index.html" style="
|
154
|
+
display: inline-block;
|
155
|
+
margin-left: 20px;
|
156
|
+
padding: 8px 16px;
|
157
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
158
|
+
color: white;
|
159
|
+
text-decoration: none;
|
160
|
+
border-radius: 8px;
|
161
|
+
font-size: 14px;
|
162
|
+
font-weight: 500;
|
163
|
+
transition: transform 0.2s, box-shadow 0.2s;
|
164
|
+
vertical-align: middle;
|
165
|
+
"
|
166
|
+
onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='0 5px 15px rgba(102, 126, 234, 0.4)';"
|
167
|
+
onmouseout="this.style.transform=''; this.style.boxShadow='';">
|
168
|
+
Try New Dashboard →
|
169
|
+
</a>
|
153
170
|
<div id="connection-status" class="status-badge status-disconnected">
|
154
171
|
<span>●</span> Disconnected
|
155
172
|
</div>
|
@@ -179,6 +196,15 @@
|
|
179
196
|
<div class="metric-mini-value" id="error-count">0</div>
|
180
197
|
<div class="metric-mini-label">Errors</div>
|
181
198
|
</div>
|
199
|
+
<!-- Debug metrics for troubleshooting -->
|
200
|
+
<div class="metric-mini" style="background: rgba(255,255,255,0.05);">
|
201
|
+
<div class="metric-mini-value" id="debug-events-received">0</div>
|
202
|
+
<div class="metric-mini-label">Received</div>
|
203
|
+
</div>
|
204
|
+
<div class="metric-mini" style="background: rgba(255,255,255,0.05);">
|
205
|
+
<div class="metric-mini-value" id="debug-events-rendered">0</div>
|
206
|
+
<div class="metric-mini-label">Rendered</div>
|
207
|
+
</div>
|
182
208
|
</div>
|
183
209
|
</div>
|
184
210
|
|
@@ -390,8 +416,9 @@
|
|
390
416
|
|
391
417
|
<!-- File Tree Tab -->
|
392
418
|
<div class="tab-content" id="claude-tree-tab">
|
393
|
-
<div id="claude-tree-container" style="width: 100%; height: 100%;">
|
419
|
+
<div id="claude-tree-container" style="width: 100%; height: 100%; position: relative;">
|
394
420
|
<!-- File activity tree will be rendered here by code-viewer.js -->
|
421
|
+
<!-- This container is ISOLATED from other tabs -->
|
395
422
|
</div>
|
396
423
|
</div>
|
397
424
|
|
@@ -490,27 +517,68 @@
|
|
490
517
|
.then(() => loadModule('/static/js/components/code-tree/tree-search.js'))
|
491
518
|
.then(() => loadModule('/static/js/components/code-tree/tree-breadcrumb.js'))
|
492
519
|
.then(() => {
|
493
|
-
// Load
|
494
|
-
return loadModule('/static/js/
|
520
|
+
// CRITICAL: Load socket-client.js FIRST (dependency of socket-manager)
|
521
|
+
return loadModule('/static/js/socket-client.js');
|
522
|
+
})
|
523
|
+
.then(() => {
|
524
|
+
// CRITICAL: Load socket-manager BEFORE dashboard.js
|
525
|
+
// The source version must be loaded to make SocketManager globally available
|
526
|
+
return loadModule('/static/js/components/socket-manager.js');
|
495
527
|
})
|
496
528
|
.then(() => {
|
497
|
-
//
|
529
|
+
// Load all required dashboard dependencies BEFORE dashboard.js
|
530
|
+
// These must be available globally for the dist/dashboard.js to work
|
498
531
|
return Promise.all([
|
499
|
-
loadModule('/static/
|
532
|
+
loadModule('/static/js/components/event-viewer.js'),
|
533
|
+
loadModule('/static/js/components/module-viewer.js'),
|
534
|
+
loadModule('/static/js/components/session-manager.js'),
|
535
|
+
loadModule('/static/js/components/agent-inference.js'),
|
536
|
+
loadModule('/static/js/components/agent-hierarchy.js'),
|
537
|
+
loadModule('/static/js/components/ui-state-manager.js'),
|
538
|
+
loadModule('/static/js/components/event-processor.js'),
|
539
|
+
loadModule('/static/js/components/export-manager.js'),
|
540
|
+
loadModule('/static/js/components/working-directory.js'),
|
541
|
+
loadModule('/static/js/components/file-tool-tracker.js'),
|
542
|
+
loadModule('/static/js/components/build-tracker.js')
|
543
|
+
]);
|
544
|
+
})
|
545
|
+
.then(() => {
|
546
|
+
// Now load main components including dashboard.js which depends on the above
|
547
|
+
return Promise.all([
|
548
|
+
loadModule('/static/dist/dashboard.js'), // Use dist version that requires above components
|
500
549
|
loadModule('/static/dist/components/activity-tree.js'),
|
501
550
|
loadModule('/static/js/components/code-tree.js'), // TEMPORARY: Direct source for debugging
|
502
|
-
loadModule('/static/js/components/code-viewer.js')
|
551
|
+
loadModule('/static/js/components/code-viewer.js').catch(err => {
|
552
|
+
console.error('[CRITICAL] Failed to load code-viewer.js:', err);
|
553
|
+
throw err;
|
554
|
+
}), // Code viewer now includes file change tracking
|
503
555
|
loadModule('/static/dist/components/file-viewer.js') // File viewer for viewing file contents
|
504
556
|
]);
|
505
557
|
})
|
506
558
|
.then(() => {
|
507
559
|
console.log('All dashboard modules loaded successfully');
|
508
560
|
|
561
|
+
// Debug: Check if CodeViewer loaded
|
562
|
+
if (window.CodeViewer) {
|
563
|
+
console.log('[DEBUG] CodeViewer is available on window object');
|
564
|
+
} else {
|
565
|
+
console.error('[ERROR] CodeViewer NOT FOUND on window object!');
|
566
|
+
}
|
567
|
+
|
509
568
|
// CodeViewer will auto-initialize and handle tab switching internally
|
510
569
|
|
511
570
|
// Browser Log Viewer initialization is now handled by UIStateManager
|
512
571
|
// This prevents duplicate event handlers and tab selection conflicts
|
513
572
|
|
573
|
+
// Load bulletproof tab isolation fix
|
574
|
+
loadModule('/static/js/tab-isolation-fix.js')
|
575
|
+
.then(() => {
|
576
|
+
console.log('✅ Tab isolation fix loaded successfully');
|
577
|
+
})
|
578
|
+
.catch(err => {
|
579
|
+
console.error('❌ Failed to load tab isolation fix:', err);
|
580
|
+
});
|
581
|
+
|
514
582
|
// Hash navigation will handle default tab based on URL
|
515
583
|
// If no hash, default will be 'events' as per hashToTab mapping
|
516
584
|
// To start with File Tree, we can set hash if not present
|
@@ -522,6 +590,11 @@
|
|
522
590
|
console.log('Hash present:', window.location.hash);
|
523
591
|
}
|
524
592
|
}, 500);
|
593
|
+
})
|
594
|
+
.catch(error => {
|
595
|
+
console.error('[CRITICAL] Error loading dashboard modules:', error);
|
596
|
+
console.error('Stack trace:', error.stack);
|
597
|
+
});
|
525
598
|
|
526
599
|
// Give modules time to execute and initialize dashboard
|
527
600
|
setTimeout(() => {
|
@@ -583,9 +656,6 @@
|
|
583
656
|
console.error('Connection toggle button not found in DOM');
|
584
657
|
}
|
585
658
|
}, 1000);
|
586
|
-
}).catch(error => {
|
587
|
-
console.error('Failed to load dashboard modules:', error);
|
588
|
-
});
|
589
659
|
</script>
|
590
660
|
</body>
|
591
661
|
</html>
|
@@ -151,7 +151,7 @@ class ConnectionManagerService:
|
|
151
151
|
|
152
152
|
if loop:
|
153
153
|
# We're in an async context, create a task
|
154
|
-
|
154
|
+
loop.create_task(self._async_emit(namespace, event, data))
|
155
155
|
# Don't wait for completion to maintain low latency
|
156
156
|
if DEBUG:
|
157
157
|
print(f"✅ Async emit scheduled: {event}", file=sys.stderr)
|
@@ -219,6 +219,9 @@ class AgentDiscoveryService:
|
|
219
219
|
agent_info = {
|
220
220
|
"name": metadata.get("name", template_file.stem),
|
221
221
|
"description": metadata.get("description", "No description available"),
|
222
|
+
"type": template_data.get(
|
223
|
+
"agent_type", metadata.get("category", "agent")
|
224
|
+
), # Extract agent type
|
222
225
|
"version": template_data.get(
|
223
226
|
"agent_version",
|
224
227
|
template_data.get("version", metadata.get("version", "1.0.0")),
|
@@ -267,17 +267,21 @@ class AgentTemplateBuilder:
|
|
267
267
|
# Include tools field only if agent is clearly restricted (missing core tools or very few tools)
|
268
268
|
not has_core_tools or len(agent_tools) < 6
|
269
269
|
|
270
|
-
# Build YAML frontmatter
|
271
|
-
#
|
270
|
+
# Build YAML frontmatter with all relevant metadata from JSON template
|
271
|
+
# Include all fields that are useful for agent management and functionality
|
272
272
|
#
|
273
|
-
#
|
273
|
+
# COMPREHENSIVE AGENT FRONTMATTER FORMAT:
|
274
274
|
# - name: kebab-case agent name (required)
|
275
275
|
# - description: when/why to use this agent with examples (required, multiline)
|
276
276
|
# - model: mapped model name (required)
|
277
|
+
# - type: agent type for categorization and functionality (optional but important)
|
278
|
+
# - category: organizational category (optional)
|
277
279
|
# - color: visual identifier (optional)
|
278
280
|
# - version: agent version for update tracking (optional)
|
279
281
|
# - author: creator information (optional)
|
280
|
-
#
|
282
|
+
# - created_at: creation timestamp (optional)
|
283
|
+
# - updated_at: last update timestamp (optional)
|
284
|
+
# - tags: list of tags for search and categorization (optional)
|
281
285
|
frontmatter_lines = [
|
282
286
|
"---",
|
283
287
|
f"name: {claude_code_name}",
|
@@ -291,15 +295,28 @@ class AgentTemplateBuilder:
|
|
291
295
|
# Add model field (required for Claude Code)
|
292
296
|
frontmatter_lines.append(f"model: {model}")
|
293
297
|
|
294
|
-
# Add
|
298
|
+
# Add type field (important for agent categorization)
|
299
|
+
if agent_type and agent_type != "general":
|
300
|
+
frontmatter_lines.append(f"type: {agent_type}")
|
301
|
+
|
302
|
+
# Add optional metadata fields
|
295
303
|
if metadata.get("color"):
|
296
304
|
frontmatter_lines.append(f"color: {metadata['color']}")
|
297
|
-
if (
|
298
|
-
|
299
|
-
|
305
|
+
if metadata.get("category"):
|
306
|
+
frontmatter_lines.append(f"category: {metadata['category']}")
|
307
|
+
# Always include version field to prevent deployment comparison issues
|
308
|
+
if agent_version:
|
300
309
|
frontmatter_lines.append(f'version: "{agent_version}"')
|
301
310
|
if metadata.get("author"):
|
302
311
|
frontmatter_lines.append(f'author: "{metadata["author"]}"')
|
312
|
+
if metadata.get("created_at"):
|
313
|
+
frontmatter_lines.append(f"created_at: {metadata['created_at']}")
|
314
|
+
if metadata.get("updated_at"):
|
315
|
+
frontmatter_lines.append(f"updated_at: {metadata['updated_at']}")
|
316
|
+
# Add tags as comma-separated string if they exist (consistent with tools format)
|
317
|
+
if metadata.get("tags") and isinstance(metadata["tags"], list):
|
318
|
+
tags_str = ",".join(metadata["tags"])
|
319
|
+
frontmatter_lines.append(f"tags: {tags_str}")
|
303
320
|
|
304
321
|
frontmatter_lines.extend(
|
305
322
|
[
|
@@ -326,6 +326,7 @@ class AgentValidator:
|
|
326
326
|
"path": str(agent_file),
|
327
327
|
"description": "No description",
|
328
328
|
"version": "unknown",
|
329
|
+
"type": "agent", # Default type
|
329
330
|
}
|
330
331
|
|
331
332
|
# Extract from YAML frontmatter
|
@@ -342,6 +343,8 @@ class AgentValidator:
|
|
342
343
|
agent_info["version"] = (
|
343
344
|
stripped_line.split(":", 1)[1].strip().strip("\"'")
|
344
345
|
)
|
346
|
+
elif stripped_line.startswith("type:"):
|
347
|
+
agent_info["type"] = stripped_line.split(":", 1)[1].strip().strip("\"'")
|
345
348
|
|
346
349
|
return agent_info
|
347
350
|
|
@@ -190,10 +190,19 @@ class TemplateValidator:
|
|
190
190
|
|
191
191
|
if "tags" in metadata:
|
192
192
|
tags = metadata["tags"]
|
193
|
-
if
|
194
|
-
|
195
|
-
|
196
|
-
|
193
|
+
if isinstance(tags, str):
|
194
|
+
# Convert comma-separated string to list for validation
|
195
|
+
tag_list = [tag.strip() for tag in tags.split(",") if tag.strip()]
|
196
|
+
if len(tag_list) == 0:
|
197
|
+
result.add_warning("No tags specified", field_name="metadata.tags")
|
198
|
+
elif isinstance(tags, list):
|
199
|
+
if len(tags) == 0:
|
200
|
+
result.add_warning("No tags specified", field_name="metadata.tags")
|
201
|
+
else:
|
202
|
+
result.add_error(
|
203
|
+
"Tags should be a list or comma-separated string",
|
204
|
+
field_name="metadata.tags",
|
205
|
+
)
|
197
206
|
|
198
207
|
def _validate_capabilities(
|
199
208
|
self, capabilities: Dict[str, Any], result: ValidationResult
|
@@ -250,13 +250,10 @@ class LocalAgentTemplateManager:
|
|
250
250
|
Created LocalAgentTemplate object
|
251
251
|
"""
|
252
252
|
# Determine author based on tier
|
253
|
-
if tier == "project"
|
254
|
-
author = self.get_project_name()
|
255
|
-
else:
|
256
|
-
author = Path.home().name
|
253
|
+
author = self.get_project_name() if tier == "project" else Path.home().name
|
257
254
|
|
258
255
|
# Create template
|
259
|
-
|
256
|
+
return LocalAgentTemplate(
|
260
257
|
agent_id=agent_id,
|
261
258
|
agent_version="1.0.0",
|
262
259
|
author=author,
|
@@ -283,7 +280,6 @@ class LocalAgentTemplateManager:
|
|
283
280
|
parent_agent=parent_agent,
|
284
281
|
)
|
285
282
|
|
286
|
-
return template
|
287
283
|
|
288
284
|
def save_local_template(
|
289
285
|
self, template: LocalAgentTemplate, tier: Optional[str] = None
|
@@ -163,8 +163,7 @@ class UnifiedMonitorDaemon:
|
|
163
163
|
# environment variable to prevent infinite recursion
|
164
164
|
if self.daemon_manager.use_subprocess_daemon():
|
165
165
|
# Start using subprocess - this returns immediately in parent
|
166
|
-
|
167
|
-
return success
|
166
|
+
return self.daemon_manager.start_daemon_subprocess()
|
168
167
|
|
169
168
|
# Check if we're in subprocess mode (environment variable set)
|
170
169
|
if os.environ.get("CLAUDE_MPM_SUBPROCESS_DAEMON") == "1":
|
@@ -183,10 +183,7 @@ class DaemonManager:
|
|
183
183
|
return True
|
184
184
|
|
185
185
|
# Try to identify claude-mpm processes
|
186
|
-
|
187
|
-
return True
|
188
|
-
|
189
|
-
return False
|
186
|
+
return bool(self._kill_claude_mpm_processes())
|
190
187
|
|
191
188
|
except Exception as e:
|
192
189
|
self.logger.error(f"Error killing processes on port: {e}")
|
@@ -579,7 +576,7 @@ class DaemonManager:
|
|
579
576
|
stderr=subprocess.STDOUT if self.log_file else subprocess.DEVNULL,
|
580
577
|
start_new_session=True, # Create new process group
|
581
578
|
close_fds=(
|
582
|
-
|
579
|
+
not self.log_file
|
583
580
|
), # Keep log file open if redirecting
|
584
581
|
env=env, # Pass modified environment
|
585
582
|
)
|
@@ -115,7 +115,7 @@ class AsyncEventEmitter:
|
|
115
115
|
event: str,
|
116
116
|
data: Dict[str, Any],
|
117
117
|
force_http: bool = False,
|
118
|
-
endpoint: str = None,
|
118
|
+
endpoint: Optional[str] = None,
|
119
119
|
) -> bool:
|
120
120
|
"""
|
121
121
|
Emit event with optimal routing (direct calls vs HTTP).
|
@@ -186,7 +186,7 @@ class AsyncEventEmitter:
|
|
186
186
|
return False
|
187
187
|
|
188
188
|
async def _emit_http(
|
189
|
-
self, namespace: str, event: str, data: Dict[str, Any], endpoint: str = None
|
189
|
+
self, namespace: str, event: str, data: Dict[str, Any], endpoint: Optional[str] = None
|
190
190
|
) -> bool:
|
191
191
|
"""Emit event via HTTP with connection pooling."""
|
192
192
|
if not self._http_session:
|
@@ -248,14 +248,14 @@ class CodeAnalysisHandler:
|
|
248
248
|
self.logger.info("All analysis cache cleared")
|
249
249
|
elif cache_type == "file":
|
250
250
|
keys_to_remove = [
|
251
|
-
k for k in self.analysis_cache
|
251
|
+
k for k in self.analysis_cache if k.startswith("file:")
|
252
252
|
]
|
253
253
|
for key in keys_to_remove:
|
254
254
|
del self.analysis_cache[key]
|
255
255
|
self.logger.info("File analysis cache cleared")
|
256
256
|
elif cache_type == "directory":
|
257
257
|
keys_to_remove = [
|
258
|
-
k for k in self.analysis_cache
|
258
|
+
k for k in self.analysis_cache if k.startswith("dir:")
|
259
259
|
]
|
260
260
|
for key in keys_to_remove:
|
261
261
|
del self.analysis_cache[key]
|
@@ -281,10 +281,9 @@ class CodeAnalysisHandler:
|
|
281
281
|
try:
|
282
282
|
# Run analysis in thread pool to avoid blocking
|
283
283
|
loop = asyncio.get_event_loop()
|
284
|
-
|
284
|
+
return await loop.run_in_executor(
|
285
285
|
None, self.analyzer.analyze_file, file_path
|
286
286
|
)
|
287
|
-
return result
|
288
287
|
|
289
288
|
except Exception as e:
|
290
289
|
self.logger.error(f"Error in async file analysis: {e}")
|
@@ -305,10 +304,9 @@ class CodeAnalysisHandler:
|
|
305
304
|
try:
|
306
305
|
# Run tree building in thread pool
|
307
306
|
loop = asyncio.get_event_loop()
|
308
|
-
|
307
|
+
return await loop.run_in_executor(
|
309
308
|
None, self.builder.build_tree, dir_path, max_depth
|
310
309
|
)
|
311
|
-
return result
|
312
310
|
|
313
311
|
except Exception as e:
|
314
312
|
self.logger.error(f"Error in async directory tree building: {e}")
|
@@ -416,7 +416,7 @@ class HookHandler:
|
|
416
416
|
Returns:
|
417
417
|
Processed event data
|
418
418
|
"""
|
419
|
-
|
419
|
+
return {
|
420
420
|
"type": data.get("type", "hook"),
|
421
421
|
"subtype": data.get("subtype", "unknown"),
|
422
422
|
"timestamp": data.get("timestamp", asyncio.get_event_loop().time()),
|
@@ -428,7 +428,6 @@ class HookHandler:
|
|
428
428
|
"original_event": data, # Keep original for debugging
|
429
429
|
}
|
430
430
|
|
431
|
-
return processed
|
432
431
|
|
433
432
|
def _process_hook_event(self, data: Dict) -> Dict:
|
434
433
|
"""Process and normalize hook event data.
|
@@ -439,7 +438,7 @@ class HookHandler:
|
|
439
438
|
Returns:
|
440
439
|
Processed event data
|
441
440
|
"""
|
442
|
-
|
441
|
+
return {
|
443
442
|
"type": data.get("type"),
|
444
443
|
"timestamp": data.get("timestamp"),
|
445
444
|
"session_id": data.get("session_id"),
|
@@ -448,7 +447,6 @@ class HookHandler:
|
|
448
447
|
"processed_at": asyncio.get_event_loop().time(),
|
449
448
|
}
|
450
449
|
|
451
|
-
return processed
|
452
450
|
|
453
451
|
def _update_session_tracking(self, session_id: str, event: Dict):
|
454
452
|
"""Update session tracking with new event.
|
@@ -15,6 +15,7 @@ DESIGN DECISIONS:
|
|
15
15
|
"""
|
16
16
|
|
17
17
|
import asyncio
|
18
|
+
import contextlib
|
18
19
|
import os
|
19
20
|
import threading
|
20
21
|
import time
|
@@ -348,7 +349,7 @@ class UnifiedMonitorServer:
|
|
348
349
|
data = await request.json()
|
349
350
|
|
350
351
|
# Extract event data
|
351
|
-
|
352
|
+
data.get("namespace", "hook")
|
352
353
|
event = data.get("event", "claude_event")
|
353
354
|
event_data = data.get("data", {})
|
354
355
|
|
@@ -508,6 +509,19 @@ class UnifiedMonitorServer:
|
|
508
509
|
{"working_directory": os.getcwd(), "success": True}
|
509
510
|
)
|
510
511
|
|
512
|
+
# Monitor page routes
|
513
|
+
async def monitor_page_handler(request):
|
514
|
+
"""Serve monitor HTML pages."""
|
515
|
+
page_name = request.match_info.get("page", "agents")
|
516
|
+
static_dir = dashboard_dir / "static"
|
517
|
+
file_path = static_dir / f"{page_name}.html"
|
518
|
+
|
519
|
+
if file_path.exists() and file_path.is_file():
|
520
|
+
with open(file_path, encoding="utf-8") as f:
|
521
|
+
content = f.read()
|
522
|
+
return web.Response(text=content, content_type="text/html")
|
523
|
+
return web.Response(text="Page not found", status=404)
|
524
|
+
|
511
525
|
# Register routes
|
512
526
|
self.app.router.add_get("/", dashboard_index)
|
513
527
|
self.app.router.add_get("/health", health_check)
|
@@ -518,6 +532,17 @@ class UnifiedMonitorServer:
|
|
518
532
|
self.app.router.add_post("/api/events", api_events_handler)
|
519
533
|
self.app.router.add_post("/api/file", api_file_handler)
|
520
534
|
|
535
|
+
# Monitor page routes
|
536
|
+
self.app.router.add_get("/monitor", lambda r: monitor_page_handler(r))
|
537
|
+
self.app.router.add_get(
|
538
|
+
"/monitor/agents", lambda r: monitor_page_handler(r)
|
539
|
+
)
|
540
|
+
self.app.router.add_get("/monitor/tools", lambda r: monitor_page_handler(r))
|
541
|
+
self.app.router.add_get("/monitor/files", lambda r: monitor_page_handler(r))
|
542
|
+
self.app.router.add_get(
|
543
|
+
"/monitor/events", lambda r: monitor_page_handler(r)
|
544
|
+
)
|
545
|
+
|
521
546
|
# Static files with cache busting headers for development
|
522
547
|
static_dir = dashboard_dir / "static"
|
523
548
|
if static_dir.exists():
|
@@ -666,10 +691,8 @@ class UnifiedMonitorServer:
|
|
666
691
|
# Cancel heartbeat task if running
|
667
692
|
if self.heartbeat_task and not self.heartbeat_task.done():
|
668
693
|
self.heartbeat_task.cancel()
|
669
|
-
|
694
|
+
with contextlib.suppress(asyncio.CancelledError):
|
670
695
|
await self.heartbeat_task
|
671
|
-
except asyncio.CancelledError:
|
672
|
-
pass
|
673
696
|
self.logger.debug("Heartbeat task cancelled")
|
674
697
|
|
675
698
|
# Close the Socket.IO server first to stop accepting new connections
|
@@ -1739,7 +1739,7 @@ class CodeTreeAnalyzer:
|
|
1739
1739
|
|
1740
1740
|
# Filter only very specific internal patterns
|
1741
1741
|
# Be more conservative - only filter obvious internal handlers
|
1742
|
-
if name_lower.startswith("handle_"
|
1742
|
+
if name_lower.startswith(("handle_", "on_")):
|
1743
1743
|
return True
|
1744
1744
|
|
1745
1745
|
# Filter Python magic methods except important ones
|
@@ -1756,7 +1756,7 @@ class CodeTreeAnalyzer:
|
|
1756
1756
|
return node.name not in important_magic
|
1757
1757
|
|
1758
1758
|
# Filter very generic getters/setters only if they're trivial
|
1759
|
-
if (name_lower.startswith("get_"
|
1759
|
+
if (name_lower.startswith(("get_", "set_"))) and len(
|
1760
1760
|
node.name
|
1761
1761
|
) <= 8:
|
1762
1762
|
return True
|