claude-mpm 4.1.21__py3-none-any.whl → 4.1.23__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.
@@ -134,6 +134,8 @@ class UnifiedDataViewer {
134
134
 
135
135
  /**
136
136
  * Display event data with comprehensive formatting
137
+ * PRIMARY: Event type, timestamp, and key details
138
+ * SECONDARY: Full event data in collapsible JSON
137
139
  */
138
140
  displayEvent(data) {
139
141
  const eventType = this.formatEventType(data);
@@ -147,19 +149,45 @@ class UnifiedDataViewer {
147
149
  <div class="unified-viewer-content">
148
150
  `;
149
151
 
150
- // Event-specific details
152
+ // PRIMARY DATA: Event-specific key details
153
+ html += `<div class="primary-data">`;
151
154
  html += this.formatEventDetails(data);
152
-
153
- // Tool parameters if present
154
- if (data.tool_parameters || (data.data && data.data.tool_parameters)) {
155
- const params = data.tool_parameters || data.data.tool_parameters;
156
- html += this.formatParameters(params, 'Tool Parameters');
155
+
156
+ // Show important tool parameters inline if present
157
+ if (data.tool_name || data.data?.tool_name) {
158
+ const toolName = data.tool_name || data.data.tool_name;
159
+ html += `
160
+ <div class="detail-row highlight">
161
+ <span class="detail-label">Tool:</span>
162
+ <span class="detail-value">${this.getToolIcon(toolName)} ${toolName}</span>
163
+ </div>
164
+ `;
165
+
166
+ // Show key parameters for specific tools
167
+ const params = data.tool_parameters || data.data?.tool_parameters;
168
+ if (params) {
169
+ if (params.file_path) {
170
+ html += `
171
+ <div class="detail-row">
172
+ <span class="detail-label">File:</span>
173
+ <span class="detail-value code">${params.file_path}</span>
174
+ </div>
175
+ `;
176
+ }
177
+ if (params.command) {
178
+ html += `
179
+ <div class="detail-row">
180
+ <span class="detail-label">Command:</span>
181
+ <pre class="code-snippet">${this.escapeHtml(params.command)}</pre>
182
+ </div>
183
+ `;
184
+ }
185
+ }
157
186
  }
187
+ html += `</div>`;
158
188
 
159
- // Event data if present
160
- if (data.data && Object.keys(data.data).length > 0) {
161
- html += this.formatEventData(data);
162
- }
189
+ // SECONDARY DATA: Collapsible JSON viewer for full event data
190
+ html += this.createCollapsibleJSON(data, 'Full Event Data');
163
191
 
164
192
  html += '</div>';
165
193
  this.container.innerHTML = html;
@@ -167,212 +195,353 @@ class UnifiedDataViewer {
167
195
 
168
196
  /**
169
197
  * Display agent data with full details
198
+ * PRIMARY: Agent status, active tools, and key info
199
+ * SECONDARY: Full agent data in collapsible JSON
170
200
  */
171
201
  displayAgent(data) {
172
202
  const agentIcon = this.getAgentIcon(data.name || data.agentName);
203
+ const agentName = data.name || data.agentName || 'Unknown Agent';
173
204
  const status = this.formatStatus(data.status);
174
205
 
175
206
  let html = `
176
207
  <div class="unified-viewer-header">
177
- <h6>${agentIcon} ${data.name || data.agentName || 'Unknown Agent'}</h6>
208
+ <h6>${agentIcon} ${agentName}</h6>
178
209
  <span class="unified-viewer-status">${status}</span>
179
210
  </div>
180
211
  <div class="unified-viewer-content">
181
- <div class="detail-row">
182
- <span class="detail-label">Status:</span>
183
- <span class="detail-value">${status}</span>
184
- </div>
185
- <div class="detail-row">
186
- <span class="detail-label">Session ID:</span>
187
- <span class="detail-value">${data.sessionId || data.session_id || 'N/A'}</span>
188
- </div>
189
- <div class="detail-row">
190
- <span class="detail-label">Timestamp:</span>
191
- <span class="detail-value">${this.formatTimestamp(data.timestamp)}</span>
192
- </div>
193
212
  `;
194
213
 
195
- // Tools used by agent
214
+ // PRIMARY DATA: Key agent information
215
+ html += `<div class="primary-data">`;
216
+
217
+ // Status with visual indicator
218
+ html += `
219
+ <div class="detail-row highlight">
220
+ <span class="detail-label">Status:</span>
221
+ <span class="detail-value ${this.formatStatusClass(status)}">${status}</span>
222
+ </div>
223
+ `;
224
+
225
+ // Tools summary if present
196
226
  if (data.tools && data.tools.length > 0) {
227
+ // Show active tools prominently
228
+ const activeTools = data.tools.filter(t => t.status === 'in_progress');
229
+ const completedTools = data.tools.filter(t => t.status === 'completed');
230
+
231
+ if (activeTools.length > 0) {
232
+ html += `
233
+ <div class="active-tools-section">
234
+ <span class="section-label">🔄 Active Tools:</span>
235
+ <div class="tools-grid">
236
+ `;
237
+ activeTools.forEach(tool => {
238
+ html += `
239
+ <div class="tool-chip active">
240
+ ${this.getToolIcon(tool.name)} ${tool.name}
241
+ </div>
242
+ `;
243
+ });
244
+ html += `</div></div>`;
245
+ }
246
+
197
247
  html += `
198
- <div class="detail-section">
199
- <span class="detail-section-title">Tools Used (${data.tools.length}):</span>
200
- <div class="tools-list">
201
- ${data.tools.map(tool => `
202
- <div class="tool-summary">
203
- <span class="tool-icon">${this.getToolIcon(tool.name)}</span>
204
- <span class="tool-name">${tool.name}</span>
205
- <span class="tool-status ${this.formatStatusClass(tool.status)}">${tool.status}</span>
206
- </div>
207
- `).join('')}
208
- </div>
248
+ <div class="detail-row">
249
+ <span class="detail-label">Tools Summary:</span>
250
+ <span class="detail-value">
251
+ ${activeTools.length} active, ${completedTools.length} completed, ${data.tools.length} total
252
+ </span>
209
253
  </div>
210
254
  `;
211
255
  }
212
256
 
257
+ // Current task if available
258
+ if (data.currentTask || data.description) {
259
+ html += `
260
+ <div class="detail-row">
261
+ <span class="detail-label">Current Task:</span>
262
+ <span class="detail-value">${data.currentTask || data.description}</span>
263
+ </div>
264
+ `;
265
+ }
266
+
267
+ html += `</div>`;
268
+
269
+ // SECONDARY DATA: Collapsible JSON viewer
270
+ html += this.createCollapsibleJSON(data, 'Full Agent Details');
271
+
213
272
  html += '</div>';
214
273
  this.container.innerHTML = html;
215
274
  }
216
275
 
217
276
  /**
218
277
  * Display tool data with parameters and results
278
+ * Special handling for TodoWrite to show todos prominently
219
279
  */
220
280
  displayTool(data) {
221
- const toolIcon = this.getToolIcon(data.name || data.tool_name);
281
+ const toolName = data.name || data.tool_name || 'Unknown Tool';
282
+ const toolIcon = this.getToolIcon(toolName);
222
283
  const status = this.formatStatus(data.status);
223
284
 
285
+ // Special handling for TodoWrite tool
286
+ if (toolName === 'TodoWrite') {
287
+ this.displayTodoWriteTool(data);
288
+ return;
289
+ }
290
+
224
291
  let html = `
225
292
  <div class="unified-viewer-header">
226
- <h6>${toolIcon} ${data.name || data.tool_name || 'Unknown Tool'}</h6>
293
+ <h6>${toolIcon} ${toolName}</h6>
227
294
  <span class="unified-viewer-status">${status}</span>
228
295
  </div>
229
296
  <div class="unified-viewer-content">
297
+ `;
298
+
299
+ // PRIMARY DATA: Show important tool-specific information first
300
+ const params = data.params || data.tool_parameters || {};
301
+
302
+ // Tool-specific primary data display
303
+ if (toolName === 'Read' || toolName === 'Edit' || toolName === 'Write') {
304
+ // File tools - show file path prominently
305
+ if (params.file_path) {
306
+ html += `
307
+ <div class="primary-data">
308
+ <div class="detail-row highlight">
309
+ <span class="detail-label">📁 File:</span>
310
+ <span class="detail-value code">${params.file_path}</span>
311
+ </div>
312
+ `;
313
+ if (params.old_string) {
314
+ html += `
315
+ <div class="detail-row">
316
+ <span class="detail-label">Old Text:</span>
317
+ <pre class="code-snippet">${this.escapeHtml(params.old_string.substring(0, 200))}${params.old_string.length > 200 ? '...' : ''}</pre>
318
+ </div>
319
+ `;
320
+ }
321
+ if (params.new_string) {
322
+ html += `
323
+ <div class="detail-row">
324
+ <span class="detail-label">New Text:</span>
325
+ <pre class="code-snippet">${this.escapeHtml(params.new_string.substring(0, 200))}${params.new_string.length > 200 ? '...' : ''}</pre>
326
+ </div>
327
+ `;
328
+ }
329
+ html += '</div>';
330
+ }
331
+ } else if (toolName === 'Bash') {
332
+ // Bash tool - show command prominently
333
+ if (params.command) {
334
+ html += `
335
+ <div class="primary-data">
336
+ <div class="detail-row highlight">
337
+ <span class="detail-label">💻 Command:</span>
338
+ <pre class="code-snippet">${this.escapeHtml(params.command)}</pre>
339
+ </div>
340
+ </div>
341
+ `;
342
+ }
343
+ } else if (toolName === 'Grep' || toolName === 'Glob') {
344
+ // Search tools - show pattern prominently
345
+ if (params.pattern) {
346
+ html += `
347
+ <div class="primary-data">
348
+ <div class="detail-row highlight">
349
+ <span class="detail-label">🔍 Pattern:</span>
350
+ <span class="detail-value code">${this.escapeHtml(params.pattern)}</span>
351
+ </div>
352
+ `;
353
+ if (params.path) {
354
+ html += `
355
+ <div class="detail-row">
356
+ <span class="detail-label">Path:</span>
357
+ <span class="detail-value">${params.path}</span>
358
+ </div>
359
+ `;
360
+ }
361
+ html += '</div>';
362
+ }
363
+ } else if (toolName === 'Task') {
364
+ // Task tool - show delegation info prominently
365
+ if (params.subagent_type) {
366
+ html += `
367
+ <div class="primary-data">
368
+ <div class="detail-row highlight">
369
+ <span class="detail-label">🤖 Delegating to:</span>
370
+ <span class="detail-value">${params.subagent_type} agent</span>
371
+ </div>
372
+ `;
373
+ if (params.description) {
374
+ html += `
375
+ <div class="detail-row">
376
+ <span class="detail-label">Task:</span>
377
+ <span class="detail-value">${params.description}</span>
378
+ </div>
379
+ `;
380
+ }
381
+ html += '</div>';
382
+ }
383
+ }
384
+
385
+ // Status and metadata
386
+ html += `
387
+ <div class="detail-row">
388
+ <span class="detail-label">Status:</span>
389
+ <span class="detail-value">${status}</span>
390
+ </div>
391
+ `;
392
+
393
+ if (data.callCount) {
394
+ html += `
230
395
  <div class="detail-row">
231
- <span class="detail-label">Type:</span>
232
- <span class="detail-value">Tool</span>
233
- </div>
234
- <div class="detail-row">
235
- <span class="detail-label">Name:</span>
236
- <span class="detail-value">${data.name || data.tool_name || 'Unknown Tool'}</span>
237
- </div>
238
- <div class="detail-row">
239
- <span class="detail-label">Status:</span>
240
- <span class="detail-value">${status}</span>
396
+ <span class="detail-label">Call Count:</span>
397
+ <span class="detail-value">${data.callCount}</span>
241
398
  </div>
399
+ `;
400
+ }
401
+
402
+ // Collapsible JSON viewer for full details
403
+ html += this.createCollapsibleJSON(data, 'Full Tool Details');
404
+
405
+ html += '</div>';
406
+ this.container.innerHTML = html;
407
+ }
408
+
409
+ /**
410
+ * Display TodoWrite tool with todos list prominently after title
411
+ */
412
+ displayTodoWriteTool(data) {
413
+ const status = this.formatStatus(data.status);
414
+ const params = data.params || data.tool_parameters || {};
415
+ const todos = params.todos || [];
416
+
417
+ let html = `
418
+ <div class="unified-viewer-header">
419
+ <h6>📝 TodoWrite</h6>
420
+ <span class="unified-viewer-status">${status}</span>
421
+ </div>
422
+ <div class="unified-viewer-content">
242
423
  `;
243
424
 
244
- // Tool parameters
245
- if (data.params || data.tool_parameters) {
246
- const params = data.params || data.tool_parameters;
247
- html += this.formatParameters(params, 'Parameters');
248
- }
425
+ // PRIMARY DATA: Todo list and status summary immediately after title
426
+ if (todos.length > 0) {
427
+ const statusCounts = this.getTodoStatusCounts(todos);
428
+
429
+ // Status summary bar
430
+ html += `
431
+ <div class="todo-status-bar">
432
+ <div class="status-item completed">
433
+ <span class="status-icon">✅</span>
434
+ <span class="status-count">${statusCounts.completed}</span>
435
+ <span class="status-label">Done</span>
436
+ </div>
437
+ <div class="status-item in_progress">
438
+ <span class="status-icon">🔄</span>
439
+ <span class="status-count">${statusCounts.in_progress}</span>
440
+ <span class="status-label">Active</span>
441
+ </div>
442
+ <div class="status-item pending">
443
+ <span class="status-icon">⏳</span>
444
+ <span class="status-count">${statusCounts.pending}</span>
445
+ <span class="status-label">Pending</span>
446
+ </div>
447
+ </div>
448
+ `;
249
449
 
250
- // Timestamp
251
- if (data.timestamp) {
450
+ // Todo items list
451
+ html += `
452
+ <div class="todo-list-primary">
453
+ `;
454
+
455
+ todos.forEach((todo, index) => {
456
+ const statusIcon = this.getCheckboxIcon(todo.status);
457
+ const displayText = todo.status === 'in_progress' ?
458
+ (todo.activeForm || todo.content) : todo.content;
459
+ const statusClass = this.formatStatusClass(todo.status);
460
+
461
+ html += `
462
+ <div class="todo-item ${todo.status}">
463
+ <span class="todo-icon ${statusClass}">${statusIcon}</span>
464
+ <span class="todo-text">${this.escapeHtml(displayText)}</span>
465
+ ${todo.status === 'in_progress' ? '<span class="todo-badge active">ACTIVE</span>' : ''}
466
+ </div>
467
+ `;
468
+ });
469
+
470
+ html += `
471
+ </div>
472
+ `;
473
+ } else {
252
474
  html += `
253
475
  <div class="detail-row">
254
- <span class="detail-label">Timestamp:</span>
255
- <span class="detail-value">${this.formatTimestamp(data.timestamp)}</span>
476
+ <span class="detail-value">No todos in list</span>
256
477
  </div>
257
478
  `;
258
479
  }
259
480
 
260
- // Tool result
261
- if (data.result) {
481
+ // Metadata section
482
+ if (data.callCount && data.callCount > 1) {
262
483
  html += `
263
- <div class="detail-section">
264
- <span class="detail-section-title">Result:</span>
265
- <pre class="tool-result">${this.escapeHtml(JSON.stringify(data.result, null, 2))}</pre>
484
+ <div class="detail-row">
485
+ <span class="detail-label">Updates:</span>
486
+ <span class="detail-value">${data.callCount}</span>
266
487
  </div>
267
488
  `;
268
489
  }
269
490
 
491
+ // Collapsible JSON viewer for full details
492
+ html += this.createCollapsibleJSON(data, 'Full Details');
493
+
270
494
  html += '</div>';
271
495
  this.container.innerHTML = html;
272
496
  }
273
497
 
274
498
  /**
275
- * Display todo data with checklist formatting
499
+ * Display todo data with checklist formatting (for standalone todos, not TodoWrite)
276
500
  */
277
501
  displayTodo(data) {
278
- // Handle different data structures for TodoWrite
502
+ // Handle different data structures for standalone todos
279
503
  let todos;
280
504
  let toolName = 'Todo List';
281
- let timestamp = null;
282
- let status = null;
283
505
 
284
506
  if (data.todos && Array.isArray(data.todos)) {
285
- // Direct todo list format
286
507
  todos = data.todos;
287
- } else if (data.tool_parameters && data.tool_parameters.todos) {
288
- // TodoWrite tool format
289
- todos = data.tool_parameters.todos;
290
- toolName = 'TodoWrite';
291
- timestamp = data.timestamp;
292
- status = data.status;
293
508
  } else if (Array.isArray(data)) {
294
- // Array of todos
295
509
  todos = data;
296
510
  } else if (data.content && data.activeForm && data.status) {
297
- // Single todo item
298
511
  todos = [data];
299
512
  } else {
300
- // Fallback
301
513
  todos = [];
302
514
  }
303
515
 
304
516
  let html = `
305
517
  <div class="unified-viewer-header">
306
- <h6>📝 ${toolName}</h6>
307
- ${status ? `<span class="unified-viewer-status">${this.formatStatus(status)}</span>` : ''}
518
+ <h6>📋 ${toolName}</h6>
308
519
  </div>
309
520
  <div class="unified-viewer-content">
310
521
  `;
311
522
 
312
- // Show timestamp if available
313
- if (timestamp) {
314
- html += `
315
- <div class="detail-row">
316
- <span class="detail-label">Timestamp:</span>
317
- <span class="detail-value">${this.formatTimestamp(timestamp)}</span>
318
- </div>
319
- `;
320
- }
321
-
322
523
  if (todos.length > 0) {
323
- // Status summary with enhanced formatting
324
- const statusCounts = this.getTodoStatusCounts(todos);
325
- html += `
326
- <div class="detail-section">
327
- <span class="detail-section-title">Todo Summary</span>
328
- <div class="todo-summary">
329
- <div class="summary-item completed">
330
- <span class="summary-icon">✅</span>
331
- <span class="summary-count">${statusCounts.completed}</span>
332
- <span class="summary-label">Completed</span>
333
- </div>
334
- <div class="summary-item in_progress">
335
- <span class="summary-icon">🔄</span>
336
- <span class="summary-count">${statusCounts.in_progress}</span>
337
- <span class="summary-label">In Progress</span>
338
- </div>
339
- <div class="summary-item pending">
340
- <span class="summary-icon">⏳</span>
341
- <span class="summary-count">${statusCounts.pending}</span>
342
- <span class="summary-label">Pending</span>
343
- </div>
344
- </div>
345
- </div>
346
- `;
347
-
348
- // Enhanced todo items display
524
+ // Show todos immediately
349
525
  html += `
350
- <div class="detail-section">
351
- <span class="detail-section-title">Todo List (${todos.length} items)</span>
352
- <div class="todo-checklist">
526
+ <div class="todo-list-primary">
353
527
  `;
354
528
 
355
- todos.forEach((todo, index) => {
529
+ todos.forEach((todo) => {
356
530
  const statusIcon = this.getCheckboxIcon(todo.status);
357
531
  const displayText = todo.status === 'in_progress' ?
358
532
  (todo.activeForm || todo.content) : todo.content;
359
533
  const statusClass = this.formatStatusClass(todo.status);
360
534
 
361
535
  html += `
362
- <div class="todo-checklist-item ${todo.status}">
363
- <div class="todo-checkbox">
364
- <span class="checkbox-icon ${statusClass}">${statusIcon}</span>
365
- </div>
366
- <div class="todo-text">
367
- <span class="todo-content">${this.escapeHtml(displayText)}</span>
368
- <span class="todo-status-badge ${statusClass}">${todo.status.replace('_', ' ')}</span>
369
- </div>
536
+ <div class="todo-item ${todo.status}">
537
+ <span class="todo-icon ${statusClass}">${statusIcon}</span>
538
+ <span class="todo-text">${this.escapeHtml(displayText)}</span>
539
+ <span class="todo-status-text ${statusClass}">${todo.status.replace('_', ' ')}</span>
370
540
  </div>
371
541
  `;
372
542
  });
373
543
 
374
544
  html += `
375
- </div>
376
545
  </div>
377
546
  `;
378
547
  } else {
@@ -389,6 +558,8 @@ class UnifiedDataViewer {
389
558
 
390
559
  /**
391
560
  * Display instruction data
561
+ * PRIMARY: Instruction text prominently displayed
562
+ * SECONDARY: Metadata in collapsible section
392
563
  */
393
564
  displayInstruction(data) {
394
565
  let html = `
@@ -397,16 +568,27 @@ class UnifiedDataViewer {
397
568
  <span class="unified-viewer-timestamp">${this.formatTimestamp(data.timestamp)}</span>
398
569
  </div>
399
570
  <div class="unified-viewer-content">
400
- <div class="detail-row">
401
- <span class="detail-label">Content:</span>
402
- <div class="detail-value instruction-text">${this.escapeHtml(data.text)}</div>
571
+ `;
572
+
573
+ // PRIMARY DATA: The instruction text itself
574
+ html += `
575
+ <div class="primary-data">
576
+ <div class="instruction-content">
577
+ ${this.escapeHtml(data.text)}
403
578
  </div>
404
- <div class="detail-row">
405
- <span class="detail-label">Length:</span>
406
- <span class="detail-value">${data.text.length} characters</span>
579
+ <div class="instruction-meta">
580
+ <span class="meta-item">📏 ${data.text.length} characters</span>
581
+ <span class="meta-item">🕐 ${this.formatTimestamp(data.timestamp)}</span>
407
582
  </div>
408
583
  </div>
409
584
  `;
585
+
586
+ // SECONDARY DATA: Full instruction object if there's more data
587
+ if (Object.keys(data).length > 3) {
588
+ html += this.createCollapsibleJSON(data, 'Full Instruction Data');
589
+ }
590
+
591
+ html += '</div>';
410
592
  this.container.innerHTML = html;
411
593
  }
412
594
 
@@ -1023,6 +1205,69 @@ class UnifiedDataViewer {
1023
1205
  return div.innerHTML;
1024
1206
  }
1025
1207
 
1208
+ /**
1209
+ * Create a collapsible JSON viewer for secondary details
1210
+ * Provides a clean way to show full data without cluttering the main view
1211
+ */
1212
+ createCollapsibleJSON(data, title = 'Full Details') {
1213
+ // Generate unique ID for this collapsible section
1214
+ const sectionId = `json-details-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1215
+
1216
+ // Filter out sensitive or overly verbose properties
1217
+ const cleanData = this.cleanDataForDisplay(data);
1218
+
1219
+ return `
1220
+ <div class="collapsible-json-section">
1221
+ <button class="collapsible-json-toggle" onclick="
1222
+ const content = document.getElementById('${sectionId}');
1223
+ const button = this;
1224
+ if (content.style.display === 'none' || content.style.display === '') {
1225
+ content.style.display = 'block';
1226
+ button.classList.add('expanded');
1227
+ button.innerHTML = '▼ ${title}';
1228
+ } else {
1229
+ content.style.display = 'none';
1230
+ button.classList.remove('expanded');
1231
+ button.innerHTML = '▶ ${title}';
1232
+ }
1233
+ ">▶ ${title}</button>
1234
+ <div id="${sectionId}" class="collapsible-json-content" style="display: none;">
1235
+ <pre class="json-viewer">${this.escapeHtml(JSON.stringify(cleanData, null, 2))}</pre>
1236
+ </div>
1237
+ </div>
1238
+ `;
1239
+ }
1240
+
1241
+ /**
1242
+ * Clean data for display in JSON viewer
1243
+ * Removes circular references and limits string lengths
1244
+ */
1245
+ cleanDataForDisplay(data) {
1246
+ const seen = new WeakSet();
1247
+
1248
+ return JSON.parse(JSON.stringify(data, (key, value) => {
1249
+ // Handle circular references
1250
+ if (typeof value === 'object' && value !== null) {
1251
+ if (seen.has(value)) {
1252
+ return '[Circular Reference]';
1253
+ }
1254
+ seen.add(value);
1255
+ }
1256
+
1257
+ // Truncate very long strings
1258
+ if (typeof value === 'string' && value.length > 1000) {
1259
+ return value.substring(0, 1000) + '... [truncated]';
1260
+ }
1261
+
1262
+ // Handle functions
1263
+ if (typeof value === 'function') {
1264
+ return '[Function]';
1265
+ }
1266
+
1267
+ return value;
1268
+ }));
1269
+ }
1270
+
1026
1271
  // ==================== PUBLIC API METHODS ====================
1027
1272
 
1028
1273
  /**
@@ -236,7 +236,12 @@ class AgentVersionManager:
236
236
  deployed_content = deployed_file.read_text()
237
237
 
238
238
  # Skip non-system agents (user-created)
239
- if "author: claude-mpm" not in deployed_content:
239
+ # Check for various author formats used by system agents
240
+ if not any(author in deployed_content.lower() for author in [
241
+ "author: claude-mpm",
242
+ "author: claude mpm team",
243
+ "author: claude mpm"
244
+ ]):
240
245
  return (False, "not a system agent")
241
246
 
242
247
  # Extract version info from YAML frontmatter
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.1.21
3
+ Version: 4.1.23
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team