claude-mpm 4.1.22__py3-none-any.whl → 4.1.24__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/dashboard/static/css/activity.css +272 -0
- claude_mpm/dashboard/static/dist/chunks/unified-data-viewer.B7wmm2bD.js +2 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/js/components/activity-tree.js +140 -51
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +365 -132
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/METADATA +1 -1
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/RECORD +15 -14
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/top_level.txt +0 -0
|
@@ -24,6 +24,24 @@ class ActivityTree {
|
|
|
24
24
|
this.expandedAgents = new Set();
|
|
25
25
|
this.expandedTools = new Set();
|
|
26
26
|
this.selectedItem = null;
|
|
27
|
+
|
|
28
|
+
// Add debounce for renderTree to prevent excessive DOM rebuilds
|
|
29
|
+
this.renderTreeDebounced = this.debounce(() => this.renderTree(), 100);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Debounce helper to prevent excessive DOM updates
|
|
34
|
+
*/
|
|
35
|
+
debounce(func, wait) {
|
|
36
|
+
let timeout;
|
|
37
|
+
return function executedFunction(...args) {
|
|
38
|
+
const later = () => {
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
func(...args);
|
|
41
|
+
};
|
|
42
|
+
clearTimeout(timeout);
|
|
43
|
+
timeout = setTimeout(later, wait);
|
|
44
|
+
};
|
|
27
45
|
}
|
|
28
46
|
|
|
29
47
|
/**
|
|
@@ -223,7 +241,6 @@ class ActivityTree {
|
|
|
223
241
|
userInstructions: [],
|
|
224
242
|
tools: [],
|
|
225
243
|
toolsMap: new Map(),
|
|
226
|
-
todoWritesMap: new Map(),
|
|
227
244
|
status: 'active',
|
|
228
245
|
currentTodoTool: null,
|
|
229
246
|
// Preserve additional session metadata
|
|
@@ -234,10 +251,16 @@ class ActivityTree {
|
|
|
234
251
|
this.sessions.set(sessionId, activitySession);
|
|
235
252
|
} else {
|
|
236
253
|
// Update existing session metadata without clearing accumulated data
|
|
254
|
+
// CRITICAL: Preserve all accumulated data (tools, agents, todos, etc.)
|
|
237
255
|
const existingSession = this.sessions.get(sessionId);
|
|
238
256
|
existingSession.timestamp = new Date(sessionData.lastActivity || sessionData.startTime || existingSession.timestamp);
|
|
239
257
|
existingSession.eventCount = sessionData.eventCount;
|
|
240
258
|
existingSession.status = sessionData.status || existingSession.status;
|
|
259
|
+
// Update metadata without losing accumulated data
|
|
260
|
+
existingSession.working_directory = sessionData.working_directory || existingSession.working_directory;
|
|
261
|
+
existingSession.git_branch = sessionData.git_branch || existingSession.git_branch;
|
|
262
|
+
// DO NOT reset tools, agents, todos, userInstructions, toolsMap, etc.
|
|
263
|
+
// These are built up from events and must be preserved!
|
|
241
264
|
}
|
|
242
265
|
}
|
|
243
266
|
|
|
@@ -258,7 +281,8 @@ class ActivityTree {
|
|
|
258
281
|
}
|
|
259
282
|
|
|
260
283
|
this.events = [...events];
|
|
261
|
-
|
|
284
|
+
// Use debounced render to prevent excessive DOM rebuilds
|
|
285
|
+
this.renderTreeDebounced();
|
|
262
286
|
|
|
263
287
|
// Debug: Log session state after processing
|
|
264
288
|
console.log(`ActivityTree: Sessions after sync with socket client:`, Array.from(this.sessions.entries()));
|
|
@@ -285,7 +309,6 @@ class ActivityTree {
|
|
|
285
309
|
userInstructions: [],
|
|
286
310
|
tools: [],
|
|
287
311
|
toolsMap: new Map(),
|
|
288
|
-
todoWritesMap: new Map(),
|
|
289
312
|
status: 'active',
|
|
290
313
|
currentTodoTool: null,
|
|
291
314
|
working_directory: sessionData.working_directory,
|
|
@@ -312,6 +335,7 @@ class ActivityTree {
|
|
|
312
335
|
}
|
|
313
336
|
|
|
314
337
|
this.events = [...socketState.events];
|
|
338
|
+
// Initial render can be immediate
|
|
315
339
|
this.renderTree();
|
|
316
340
|
|
|
317
341
|
// Debug: Log initial session state
|
|
@@ -382,7 +406,8 @@ class ActivityTree {
|
|
|
382
406
|
this.processUserInstruction(event, session);
|
|
383
407
|
break;
|
|
384
408
|
case 'TodoWrite':
|
|
385
|
-
|
|
409
|
+
// TodoWrite is now handled as a tool in 'tool_use' events
|
|
410
|
+
// Skip separate TodoWrite processing to avoid duplication
|
|
386
411
|
break;
|
|
387
412
|
case 'SubagentStart':
|
|
388
413
|
this.processSubagentStart(event, session);
|
|
@@ -639,14 +664,12 @@ class ActivityTree {
|
|
|
639
664
|
timestamp: event.timestamp,
|
|
640
665
|
status: 'active',
|
|
641
666
|
tools: [],
|
|
642
|
-
todoWrites: [], // Store TodoWrite instances
|
|
643
667
|
subagents: new Map(), // Store nested subagents
|
|
644
668
|
sessionId: agentSessionId,
|
|
645
669
|
parentAgent: parentAgent,
|
|
646
670
|
isPM: agentName.toLowerCase() === 'pm' || agentName.toLowerCase().includes('project manager'),
|
|
647
671
|
instanceCount: 1,
|
|
648
|
-
toolsMap: new Map()
|
|
649
|
-
todoWritesMap: new Map() // Track unique TodoWrites
|
|
672
|
+
toolsMap: new Map() // Track unique tools by name
|
|
650
673
|
};
|
|
651
674
|
|
|
652
675
|
// If this is a subagent, nest it under the parent agent
|
|
@@ -698,6 +721,12 @@ class ActivityTree {
|
|
|
698
721
|
|
|
699
722
|
/**
|
|
700
723
|
* Process tool use event
|
|
724
|
+
*
|
|
725
|
+
* DISPLAY RULES:
|
|
726
|
+
* 1. TodoWrite is a privileged tool that ALWAYS appears first under the agent/PM
|
|
727
|
+
* 2. Each tool appears only once per unique instance (updated in place)
|
|
728
|
+
* 3. Tools are listed in order of creation (after TodoWrite)
|
|
729
|
+
* 4. Tool instances are updated with new events as they arrive
|
|
701
730
|
*/
|
|
702
731
|
processToolUse(event, session) {
|
|
703
732
|
const toolName = event.tool_name || event.data?.tool_name || event.tool || event.data?.tool || 'unknown';
|
|
@@ -723,11 +752,13 @@ class ActivityTree {
|
|
|
723
752
|
targetAgent.tools = [];
|
|
724
753
|
}
|
|
725
754
|
|
|
726
|
-
// Check if we already have this tool
|
|
727
|
-
|
|
755
|
+
// Check if we already have this tool instance
|
|
756
|
+
// Use tool name + params hash for unique identification
|
|
757
|
+
const toolKey = this.getToolKey(toolName, params);
|
|
758
|
+
let existingTool = targetAgent.toolsMap.get(toolKey);
|
|
728
759
|
|
|
729
760
|
if (existingTool) {
|
|
730
|
-
// Update existing tool instance
|
|
761
|
+
// UPDATE RULE: Update existing tool instance in place
|
|
731
762
|
existingTool.params = params;
|
|
732
763
|
existingTool.timestamp = event.timestamp;
|
|
733
764
|
existingTool.status = 'in_progress';
|
|
@@ -737,7 +768,7 @@ class ActivityTree {
|
|
|
737
768
|
// Update current tool for collapsed display
|
|
738
769
|
targetAgent.currentTool = existingTool;
|
|
739
770
|
} else {
|
|
740
|
-
// Create new tool instance
|
|
771
|
+
// CREATE RULE: Create new tool instance
|
|
741
772
|
const tool = {
|
|
742
773
|
id: `tool-${targetAgent.id}-${toolName}-${Date.now()}`,
|
|
743
774
|
name: toolName,
|
|
@@ -747,7 +778,8 @@ class ActivityTree {
|
|
|
747
778
|
status: 'in_progress',
|
|
748
779
|
params: params,
|
|
749
780
|
eventId: event.id,
|
|
750
|
-
callCount: 1
|
|
781
|
+
callCount: 1,
|
|
782
|
+
createdAt: event.timestamp // Track creation order
|
|
751
783
|
};
|
|
752
784
|
|
|
753
785
|
// Special handling for Task tool (subagent delegation)
|
|
@@ -756,12 +788,22 @@ class ActivityTree {
|
|
|
756
788
|
tool.subagentType = params.subagent_type;
|
|
757
789
|
}
|
|
758
790
|
|
|
759
|
-
targetAgent.toolsMap.set(
|
|
760
|
-
|
|
791
|
+
targetAgent.toolsMap.set(toolKey, tool);
|
|
792
|
+
|
|
793
|
+
// ORDERING RULE: TodoWrite always goes first, others in creation order
|
|
794
|
+
if (toolName === 'TodoWrite') {
|
|
795
|
+
// Insert TodoWrite at the beginning
|
|
796
|
+
targetAgent.tools.unshift(tool);
|
|
797
|
+
} else {
|
|
798
|
+
// Append other tools in creation order
|
|
799
|
+
targetAgent.tools.push(tool);
|
|
800
|
+
}
|
|
801
|
+
|
|
761
802
|
targetAgent.currentTool = tool;
|
|
762
803
|
}
|
|
763
804
|
} else {
|
|
764
805
|
// No agent found, attach to session (PM level)
|
|
806
|
+
// PM RULE: Same display rules apply - TodoWrite first, others in creation order
|
|
765
807
|
if (!session.tools) {
|
|
766
808
|
session.tools = [];
|
|
767
809
|
}
|
|
@@ -769,9 +811,11 @@ class ActivityTree {
|
|
|
769
811
|
session.toolsMap = new Map();
|
|
770
812
|
}
|
|
771
813
|
|
|
772
|
-
|
|
814
|
+
const toolKey = this.getToolKey(toolName, params);
|
|
815
|
+
let existingTool = session.toolsMap.get(toolKey);
|
|
773
816
|
|
|
774
817
|
if (existingTool) {
|
|
818
|
+
// UPDATE RULE: Update existing tool instance in place
|
|
775
819
|
existingTool.params = params;
|
|
776
820
|
existingTool.timestamp = event.timestamp;
|
|
777
821
|
existingTool.status = 'in_progress';
|
|
@@ -788,23 +832,69 @@ class ActivityTree {
|
|
|
788
832
|
status: 'in_progress',
|
|
789
833
|
params: params,
|
|
790
834
|
eventId: event.id,
|
|
791
|
-
callCount: 1
|
|
835
|
+
callCount: 1,
|
|
836
|
+
createdAt: event.timestamp // Track creation order
|
|
792
837
|
};
|
|
793
838
|
|
|
794
|
-
session.toolsMap.set(
|
|
795
|
-
|
|
839
|
+
session.toolsMap.set(toolKey, tool);
|
|
840
|
+
|
|
841
|
+
// ORDERING RULE: TodoWrite always goes first for PM too
|
|
842
|
+
if (toolName === 'TodoWrite') {
|
|
843
|
+
session.tools.unshift(tool);
|
|
844
|
+
} else {
|
|
845
|
+
session.tools.push(tool);
|
|
846
|
+
}
|
|
847
|
+
|
|
796
848
|
session.currentTool = tool;
|
|
797
849
|
}
|
|
798
850
|
}
|
|
799
851
|
}
|
|
800
852
|
|
|
853
|
+
/**
|
|
854
|
+
* Generate unique key for tool instance identification
|
|
855
|
+
* Tools are unique per name + certain parameter combinations
|
|
856
|
+
*/
|
|
857
|
+
getToolKey(toolName, params) {
|
|
858
|
+
// For TodoWrite, we want ONE instance per agent/PM that updates in place
|
|
859
|
+
// So we use just the tool name as the key
|
|
860
|
+
if (toolName === 'TodoWrite') {
|
|
861
|
+
return 'TodoWrite'; // Single instance per agent/PM
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// For other tools, we generally want one instance per tool type
|
|
865
|
+
// that gets updated with each call (not creating new instances)
|
|
866
|
+
let key = toolName;
|
|
867
|
+
|
|
868
|
+
// Only add distinguishing params if we need multiple instances
|
|
869
|
+
// For example, multiple files being edited simultaneously
|
|
870
|
+
if (toolName === 'Edit' || toolName === 'Write' || toolName === 'Read') {
|
|
871
|
+
if (params.file_path) {
|
|
872
|
+
key += `-${params.file_path}`;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// For search tools, we might want separate instances for different searches
|
|
877
|
+
if ((toolName === 'Grep' || toolName === 'Glob') && params.pattern) {
|
|
878
|
+
// Only add pattern if significantly different
|
|
879
|
+
key += `-${params.pattern.substring(0, 20)}`;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Most tools should have a single instance that updates
|
|
883
|
+
// This prevents the tool list from growing unbounded
|
|
884
|
+
return key;
|
|
885
|
+
}
|
|
886
|
+
|
|
801
887
|
/**
|
|
802
888
|
* Update tool status after completion
|
|
803
889
|
*/
|
|
804
890
|
updateToolStatus(event, session, status) {
|
|
805
891
|
const toolName = event.tool_name || event.data?.tool_name || event.tool || 'unknown';
|
|
892
|
+
const params = event.tool_parameters || event.data?.tool_parameters || event.parameters || event.data?.parameters || {};
|
|
806
893
|
const agentSessionId = event.session_id || event.data?.session_id;
|
|
807
894
|
|
|
895
|
+
// Generate the same key we used to store the tool
|
|
896
|
+
const toolKey = this.getToolKey(toolName, params);
|
|
897
|
+
|
|
808
898
|
// Find the appropriate agent
|
|
809
899
|
let targetAgent = session.currentActiveAgent;
|
|
810
900
|
|
|
@@ -815,7 +905,7 @@ class ActivityTree {
|
|
|
815
905
|
}
|
|
816
906
|
|
|
817
907
|
if (targetAgent && targetAgent.toolsMap) {
|
|
818
|
-
const tool = targetAgent.toolsMap.get(
|
|
908
|
+
const tool = targetAgent.toolsMap.get(toolKey);
|
|
819
909
|
if (tool) {
|
|
820
910
|
tool.status = status;
|
|
821
911
|
tool.completedAt = event.timestamp;
|
|
@@ -831,7 +921,7 @@ class ActivityTree {
|
|
|
831
921
|
|
|
832
922
|
// Check session-level tools
|
|
833
923
|
if (session.toolsMap) {
|
|
834
|
-
const tool = session.toolsMap.get(
|
|
924
|
+
const tool = session.toolsMap.get(toolKey);
|
|
835
925
|
if (tool) {
|
|
836
926
|
tool.status = status;
|
|
837
927
|
tool.completedAt = event.timestamp;
|
|
@@ -845,7 +935,7 @@ class ActivityTree {
|
|
|
845
935
|
}
|
|
846
936
|
}
|
|
847
937
|
|
|
848
|
-
console.log(`ActivityTree: Could not find tool to update status for ${toolName} (event ${event.id})`);
|
|
938
|
+
console.log(`ActivityTree: Could not find tool to update status for ${toolName} with key ${toolKey} (event ${event.id})`);
|
|
849
939
|
}
|
|
850
940
|
|
|
851
941
|
/**
|
|
@@ -925,6 +1015,14 @@ class ActivityTree {
|
|
|
925
1015
|
|
|
926
1016
|
/**
|
|
927
1017
|
* Render session content (user instructions, todos, agents, tools)
|
|
1018
|
+
*
|
|
1019
|
+
* PM DISPLAY RULES (documented inline):
|
|
1020
|
+
* 1. User instructions appear first (context)
|
|
1021
|
+
* 2. PM-level tools follow the same rules as agent tools:
|
|
1022
|
+
* - TodoWrite is privileged and appears first
|
|
1023
|
+
* - Other tools appear in creation order
|
|
1024
|
+
* - Each unique instance is updated in place
|
|
1025
|
+
* 3. Agents appear after PM tools
|
|
928
1026
|
*/
|
|
929
1027
|
renderSessionContent(session) {
|
|
930
1028
|
let html = '';
|
|
@@ -936,13 +1034,16 @@ class ActivityTree {
|
|
|
936
1034
|
}
|
|
937
1035
|
}
|
|
938
1036
|
|
|
939
|
-
//
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1037
|
+
// PM TOOL DISPLAY RULES:
|
|
1038
|
+
// Render PM-level tools (TodoWrite first, then others in creation order)
|
|
1039
|
+
// The session.tools array is already properly ordered by processToolUse
|
|
1040
|
+
if (session.tools && session.tools.length > 0) {
|
|
1041
|
+
for (let tool of session.tools) {
|
|
1042
|
+
html += this.renderToolElement(tool, 1);
|
|
1043
|
+
}
|
|
943
1044
|
}
|
|
944
1045
|
|
|
945
|
-
// Render agents (they will have their own TodoWrite)
|
|
1046
|
+
// Render agents (they will have their own TodoWrite at the top)
|
|
946
1047
|
const agents = Array.from(session.agents.values())
|
|
947
1048
|
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
|
|
948
1049
|
|
|
@@ -950,15 +1051,6 @@ class ActivityTree {
|
|
|
950
1051
|
html += this.renderAgentElement(agent, 1);
|
|
951
1052
|
}
|
|
952
1053
|
|
|
953
|
-
// Render session-level tools LAST (excluding TodoWrite since we show it first)
|
|
954
|
-
if (session.tools && session.tools.length > 0) {
|
|
955
|
-
for (let tool of session.tools) {
|
|
956
|
-
if (tool.name !== 'TodoWrite') {
|
|
957
|
-
html += this.renderToolElement(tool, 1);
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
|
|
962
1054
|
return html;
|
|
963
1055
|
}
|
|
964
1056
|
|
|
@@ -1052,10 +1144,9 @@ class ActivityTree {
|
|
|
1052
1144
|
renderAgentElement(agent, level) {
|
|
1053
1145
|
const statusClass = agent.status === 'active' ? 'status-active' : 'status-completed';
|
|
1054
1146
|
const isExpanded = this.expandedAgents.has(agent.id);
|
|
1055
|
-
const hasTodoWrites = agent.todoWrites && agent.todoWrites.length > 0;
|
|
1056
1147
|
const hasTools = agent.tools && agent.tools.length > 0;
|
|
1057
1148
|
const hasSubagents = agent.subagents && agent.subagents.size > 0;
|
|
1058
|
-
const hasContent =
|
|
1149
|
+
const hasContent = hasTools || hasSubagents;
|
|
1059
1150
|
const isSelected = this.selectedItem && this.selectedItem.type === 'agent' && this.selectedItem.data.id === agent.id;
|
|
1060
1151
|
|
|
1061
1152
|
const expandIcon = hasContent ? (isExpanded ? '▼' : '▶') : '';
|
|
@@ -1096,10 +1187,18 @@ class ActivityTree {
|
|
|
1096
1187
|
if (hasContent && isExpanded) {
|
|
1097
1188
|
html += '<div class="tree-children">';
|
|
1098
1189
|
|
|
1099
|
-
//
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1190
|
+
// DISPLAY ORDER RULES (documented inline):
|
|
1191
|
+
// 1. TodoWrite is a privileged tool - ALWAYS appears first
|
|
1192
|
+
// 2. Each tool appears only once per unique instance
|
|
1193
|
+
// 3. Tools are displayed in order of creation (after TodoWrite)
|
|
1194
|
+
// 4. Tool instances are updated in place as new events arrive
|
|
1195
|
+
|
|
1196
|
+
// Render all tools in their proper order
|
|
1197
|
+
// The tools array is already ordered: TodoWrite first, then others by creation
|
|
1198
|
+
if (hasTools) {
|
|
1199
|
+
for (let tool of agent.tools) {
|
|
1200
|
+
html += this.renderToolElement(tool, level + 1);
|
|
1201
|
+
}
|
|
1103
1202
|
}
|
|
1104
1203
|
|
|
1105
1204
|
// Then render subagents (they will have their own TodoWrite at the top)
|
|
@@ -1110,16 +1209,6 @@ class ActivityTree {
|
|
|
1110
1209
|
}
|
|
1111
1210
|
}
|
|
1112
1211
|
|
|
1113
|
-
// Finally render other tools (excluding TodoWrite)
|
|
1114
|
-
if (hasTools) {
|
|
1115
|
-
for (let tool of agent.tools) {
|
|
1116
|
-
// Skip TodoWrite tools since we show them separately at the top
|
|
1117
|
-
if (tool.name !== 'TodoWrite') {
|
|
1118
|
-
html += this.renderToolElement(tool, level + 1);
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
1212
|
html += '</div>';
|
|
1124
1213
|
}
|
|
1125
1214
|
|