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.
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 4.1.21
1
+ 4.1.23
@@ -1683,4 +1683,256 @@ body .activity-tree-container .linear-tree .tree-node.tool.privileged-tool .tree
1683
1683
  font-size: 0.75em;
1684
1684
  margin-left: 5px;
1685
1685
  font-weight: 600;
1686
+ }
1687
+
1688
+ /* ==================== IMPROVED DATA VIEWER STYLES ==================== */
1689
+
1690
+ /* Primary data section for important information */
1691
+ .primary-data {
1692
+ padding: 10px 0;
1693
+ border-bottom: 1px solid #e5e7eb;
1694
+ margin-bottom: 15px;
1695
+ }
1696
+
1697
+ .primary-data .detail-row.highlight {
1698
+ background: rgba(59, 130, 246, 0.05);
1699
+ padding: 8px 12px;
1700
+ border-radius: 6px;
1701
+ margin: 5px 0;
1702
+ font-weight: 500;
1703
+ }
1704
+
1705
+ .primary-data .code {
1706
+ font-family: 'Monaco', 'Courier New', monospace;
1707
+ background: #1e293b;
1708
+ color: #94a3b8;
1709
+ padding: 2px 6px;
1710
+ border-radius: 3px;
1711
+ }
1712
+
1713
+ /* TodoWrite specific styles */
1714
+ .todo-status-bar {
1715
+ display: flex;
1716
+ gap: 20px;
1717
+ padding: 12px;
1718
+ background: linear-gradient(90deg, #f8fafc 0%, #f1f5f9 100%);
1719
+ border-radius: 8px;
1720
+ margin-bottom: 15px;
1721
+ }
1722
+
1723
+ .todo-status-bar .status-item {
1724
+ display: flex;
1725
+ align-items: center;
1726
+ gap: 6px;
1727
+ }
1728
+
1729
+ .todo-status-bar .status-icon {
1730
+ font-size: 1.2em;
1731
+ }
1732
+
1733
+ .todo-status-bar .status-count {
1734
+ font-size: 1.4em;
1735
+ font-weight: 700;
1736
+ color: #1e293b;
1737
+ }
1738
+
1739
+ .todo-status-bar .status-label {
1740
+ color: #64748b;
1741
+ font-size: 0.9em;
1742
+ }
1743
+
1744
+ /* Todo list primary display */
1745
+ .todo-list-primary {
1746
+ padding: 10px 0;
1747
+ }
1748
+
1749
+ .todo-item {
1750
+ display: flex;
1751
+ align-items: center;
1752
+ gap: 10px;
1753
+ padding: 10px 12px;
1754
+ margin: 5px 0;
1755
+ background: white;
1756
+ border: 1px solid #e5e7eb;
1757
+ border-radius: 6px;
1758
+ transition: all 0.2s ease;
1759
+ }
1760
+
1761
+ .todo-item:hover {
1762
+ border-color: #cbd5e1;
1763
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
1764
+ }
1765
+
1766
+ .todo-item.completed {
1767
+ opacity: 0.7;
1768
+ background: #f8fafc;
1769
+ }
1770
+
1771
+ .todo-item.completed .todo-text {
1772
+ text-decoration: line-through;
1773
+ color: #94a3b8;
1774
+ }
1775
+
1776
+ .todo-item.in_progress {
1777
+ background: linear-gradient(90deg, rgba(251, 146, 60, 0.1) 0%, white 100%);
1778
+ border-color: #fb923c;
1779
+ }
1780
+
1781
+ .todo-item .todo-icon {
1782
+ font-size: 1.2em;
1783
+ flex-shrink: 0;
1784
+ }
1785
+
1786
+ .todo-item .todo-text {
1787
+ flex-grow: 1;
1788
+ font-size: 0.95em;
1789
+ color: #334155;
1790
+ }
1791
+
1792
+ .todo-item .todo-badge.active {
1793
+ background: #fb923c;
1794
+ color: white;
1795
+ padding: 2px 8px;
1796
+ border-radius: 12px;
1797
+ font-size: 0.75em;
1798
+ font-weight: 600;
1799
+ text-transform: uppercase;
1800
+ animation: pulse 2s ease-in-out infinite;
1801
+ }
1802
+
1803
+ /* Tool display improvements */
1804
+ .tool-chip {
1805
+ display: inline-flex;
1806
+ align-items: center;
1807
+ gap: 6px;
1808
+ padding: 4px 10px;
1809
+ background: #f1f5f9;
1810
+ border: 1px solid #e2e8f0;
1811
+ border-radius: 15px;
1812
+ font-size: 0.9em;
1813
+ margin: 2px;
1814
+ }
1815
+
1816
+ .tool-chip.active {
1817
+ background: linear-gradient(90deg, #fef3c7 0%, #fed7aa 100%);
1818
+ border-color: #fb923c;
1819
+ font-weight: 500;
1820
+ }
1821
+
1822
+ .tools-grid {
1823
+ display: flex;
1824
+ flex-wrap: wrap;
1825
+ gap: 5px;
1826
+ margin-top: 8px;
1827
+ }
1828
+
1829
+ .active-tools-section {
1830
+ margin: 10px 0;
1831
+ padding: 10px;
1832
+ background: rgba(251, 146, 60, 0.05);
1833
+ border-radius: 6px;
1834
+ }
1835
+
1836
+ .active-tools-section .section-label {
1837
+ font-weight: 600;
1838
+ color: #ea580c;
1839
+ display: block;
1840
+ margin-bottom: 8px;
1841
+ }
1842
+
1843
+ /* Instruction display */
1844
+ .instruction-content {
1845
+ background: #f8fafc;
1846
+ padding: 15px;
1847
+ border-radius: 8px;
1848
+ border-left: 4px solid #3b82f6;
1849
+ font-size: 0.95em;
1850
+ line-height: 1.6;
1851
+ color: #1e293b;
1852
+ margin-bottom: 10px;
1853
+ }
1854
+
1855
+ .instruction-meta {
1856
+ display: flex;
1857
+ gap: 15px;
1858
+ padding: 8px 0;
1859
+ color: #64748b;
1860
+ font-size: 0.85em;
1861
+ }
1862
+
1863
+ .instruction-meta .meta-item {
1864
+ display: flex;
1865
+ align-items: center;
1866
+ gap: 5px;
1867
+ }
1868
+
1869
+ /* Collapsible JSON viewer */
1870
+ .collapsible-json-section {
1871
+ margin-top: 15px;
1872
+ border-top: 1px solid #e5e7eb;
1873
+ padding-top: 10px;
1874
+ }
1875
+
1876
+ .collapsible-json-toggle {
1877
+ background: #f8fafc;
1878
+ border: 1px solid #e2e8f0;
1879
+ padding: 6px 12px;
1880
+ border-radius: 6px;
1881
+ cursor: pointer;
1882
+ font-size: 0.9em;
1883
+ color: #475569;
1884
+ transition: all 0.2s ease;
1885
+ width: auto;
1886
+ display: inline-block;
1887
+ }
1888
+
1889
+ .collapsible-json-toggle:hover {
1890
+ background: #f1f5f9;
1891
+ border-color: #cbd5e1;
1892
+ }
1893
+
1894
+ .collapsible-json-toggle.expanded {
1895
+ background: #e0e7ff;
1896
+ border-color: #818cf8;
1897
+ color: #4338ca;
1898
+ }
1899
+
1900
+ .collapsible-json-content {
1901
+ margin-top: 10px;
1902
+ max-height: 400px;
1903
+ overflow-y: auto;
1904
+ }
1905
+
1906
+ .json-viewer {
1907
+ background: #1e293b;
1908
+ color: #94a3b8;
1909
+ padding: 12px;
1910
+ border-radius: 6px;
1911
+ font-family: 'Monaco', 'Courier New', monospace;
1912
+ font-size: 0.85em;
1913
+ line-height: 1.4;
1914
+ overflow-x: auto;
1915
+ }
1916
+
1917
+ /* Code snippets in viewers */
1918
+ .code-snippet {
1919
+ background: #1e293b;
1920
+ color: #94a3b8;
1921
+ padding: 8px 12px;
1922
+ border-radius: 4px;
1923
+ font-family: 'Monaco', 'Courier New', monospace;
1924
+ font-size: 0.9em;
1925
+ margin: 5px 0;
1926
+ overflow-x: auto;
1927
+ max-width: 100%;
1928
+ }
1929
+
1930
+ /* Animation for active items */
1931
+ @keyframes pulse {
1932
+ 0%, 100% {
1933
+ opacity: 1;
1934
+ }
1935
+ 50% {
1936
+ opacity: 0.7;
1937
+ }
1686
1938
  }
@@ -0,0 +1,2 @@
1
+ class s{constructor(s="module-data-content"){this.container=document.getElementById(s),this.currentData=null,this.currentType=null}display(s,a=null){if(this.container)switch(this.currentData=s,this.currentType=a,a||(a=this.detectType(s)),this.container.innerHTML="",a){case"event":this.displayEvent(s);break;case"agent":this.displayAgent(s);break;case"tool":this.displayTool(s);break;case"todo":this.displayTodo(s);break;case"instruction":this.displayInstruction(s);break;case"session":this.displaySession(s);break;case"file_operation":this.displayFileOperation(s);break;case"hook":this.displayHook(s);break;default:this.displayGeneric(s)}else console.warn("UnifiedDataViewer: Container not found")}detectType(s){return s&&"object"==typeof s?s.hook_event_name||s.event_type||s.type&&s.timestamp?"event":s.agent_name||s.agentName||s.name&&("active"===s.status||"completed"===s.status)?"agent":s.tool_name||"TodoWrite"===s.name||"Read"===s.name||s.tool_parameters||s.params&&s.icon||s.name&&"tool"===s.type?"tool":!s.todos||s.name||s.params?s.content&&s.activeForm&&s.status&&!s.name&&!s.params?"todo":s.text&&s.preview&&"user_instruction"===s.type?"instruction":s.session_id&&(s.startTime||s.lastActivity)?"session":s.file_path&&(s.operations||s.operation)?"file_operation":s.event_type&&(s.hook_name||s.subtype)?"hook":"generic":"todo":"generic"}displayEvent(s){let a=`\n <div class="unified-viewer-header">\n <h6>${this.formatEventType(s)}</h6>\n <span class="unified-viewer-timestamp">${this.formatTimestamp(s.timestamp)}</span>\n </div>\n <div class="unified-viewer-content">\n `;if(a+='<div class="primary-data">',a+=this.formatEventDetails(s),s.tool_name||s.data?.tool_name){const n=s.tool_name||s.data.tool_name;a+=`\n <div class="detail-row highlight">\n <span class="detail-label">Tool:</span>\n <span class="detail-value">${this.getToolIcon(n)} ${n}</span>\n </div>\n `;const t=s.tool_parameters||s.data?.tool_parameters;t&&(t.file_path&&(a+=`\n <div class="detail-row">\n <span class="detail-label">File:</span>\n <span class="detail-value code">${t.file_path}</span>\n </div>\n `),t.command&&(a+=`\n <div class="detail-row">\n <span class="detail-label">Command:</span>\n <pre class="code-snippet">${this.escapeHtml(t.command)}</pre>\n </div>\n `))}a+="</div>",a+=this.createCollapsibleJSON(s,"Full Event Data"),a+="</div>",this.container.innerHTML=a}displayAgent(s){const a=this.getAgentIcon(s.name||s.agentName),n=s.name||s.agentName||"Unknown Agent",t=this.formatStatus(s.status);let e=`\n <div class="unified-viewer-header">\n <h6>${a} ${n}</h6>\n <span class="unified-viewer-status">${t}</span>\n </div>\n <div class="unified-viewer-content">\n `;if(e+='<div class="primary-data">',e+=`\n <div class="detail-row highlight">\n <span class="detail-label">Status:</span>\n <span class="detail-value ${this.formatStatusClass(t)}">${t}</span>\n </div>\n `,s.tools&&s.tools.length>0){const a=s.tools.filter(s=>"in_progress"===s.status),n=s.tools.filter(s=>"completed"===s.status);a.length>0&&(e+='\n <div class="active-tools-section">\n <span class="section-label">🔄 Active Tools:</span>\n <div class="tools-grid">\n ',a.forEach(s=>{e+=`\n <div class="tool-chip active">\n ${this.getToolIcon(s.name)} ${s.name}\n </div>\n `}),e+="</div></div>"),e+=`\n <div class="detail-row">\n <span class="detail-label">Tools Summary:</span>\n <span class="detail-value">\n ${a.length} active, ${n.length} completed, ${s.tools.length} total\n </span>\n </div>\n `}(s.currentTask||s.description)&&(e+=`\n <div class="detail-row">\n <span class="detail-label">Current Task:</span>\n <span class="detail-value">${s.currentTask||s.description}</span>\n </div>\n `),e+="</div>",e+=this.createCollapsibleJSON(s,"Full Agent Details"),e+="</div>",this.container.innerHTML=e}displayTool(s){const a=s.name||s.tool_name||"Unknown Tool",n=this.getToolIcon(a),t=this.formatStatus(s.status);if("TodoWrite"===a)return void this.displayTodoWriteTool(s);let e=`\n <div class="unified-viewer-header">\n <h6>${n} ${a}</h6>\n <span class="unified-viewer-status">${t}</span>\n </div>\n <div class="unified-viewer-content">\n `;const i=s.params||s.tool_parameters||{};"Read"===a||"Edit"===a||"Write"===a?i.file_path&&(e+=`\n <div class="primary-data">\n <div class="detail-row highlight">\n <span class="detail-label">📁 File:</span>\n <span class="detail-value code">${i.file_path}</span>\n </div>\n `,i.old_string&&(e+=`\n <div class="detail-row">\n <span class="detail-label">Old Text:</span>\n <pre class="code-snippet">${this.escapeHtml(i.old_string.substring(0,200))}${i.old_string.length>200?"...":""}</pre>\n </div>\n `),i.new_string&&(e+=`\n <div class="detail-row">\n <span class="detail-label">New Text:</span>\n <pre class="code-snippet">${this.escapeHtml(i.new_string.substring(0,200))}${i.new_string.length>200?"...":""}</pre>\n </div>\n `),e+="</div>"):"Bash"===a?i.command&&(e+=`\n <div class="primary-data">\n <div class="detail-row highlight">\n <span class="detail-label">💻 Command:</span>\n <pre class="code-snippet">${this.escapeHtml(i.command)}</pre>\n </div>\n </div>\n `):"Grep"===a||"Glob"===a?i.pattern&&(e+=`\n <div class="primary-data">\n <div class="detail-row highlight">\n <span class="detail-label">🔍 Pattern:</span>\n <span class="detail-value code">${this.escapeHtml(i.pattern)}</span>\n </div>\n `,i.path&&(e+=`\n <div class="detail-row">\n <span class="detail-label">Path:</span>\n <span class="detail-value">${i.path}</span>\n </div>\n `),e+="</div>"):"Task"===a&&i.subagent_type&&(e+=`\n <div class="primary-data">\n <div class="detail-row highlight">\n <span class="detail-label">🤖 Delegating to:</span>\n <span class="detail-value">${i.subagent_type} agent</span>\n </div>\n `,i.description&&(e+=`\n <div class="detail-row">\n <span class="detail-label">Task:</span>\n <span class="detail-value">${i.description}</span>\n </div>\n `),e+="</div>"),e+=`\n <div class="detail-row">\n <span class="detail-label">Status:</span>\n <span class="detail-value">${t}</span>\n </div>\n `,s.callCount&&(e+=`\n <div class="detail-row">\n <span class="detail-label">Call Count:</span>\n <span class="detail-value">${s.callCount}</span>\n </div>\n `),e+=this.createCollapsibleJSON(s,"Full Tool Details"),e+="</div>",this.container.innerHTML=e}displayTodoWriteTool(s){const a=this.formatStatus(s.status),n=(s.params||s.tool_parameters||{}).todos||[];let t=`\n <div class="unified-viewer-header">\n <h6>📝 TodoWrite</h6>\n <span class="unified-viewer-status">${a}</span>\n </div>\n <div class="unified-viewer-content">\n `;if(n.length>0){const s=this.getTodoStatusCounts(n);t+=`\n <div class="todo-status-bar">\n <div class="status-item completed">\n <span class="status-icon">✅</span>\n <span class="status-count">${s.completed}</span>\n <span class="status-label">Done</span>\n </div>\n <div class="status-item in_progress">\n <span class="status-icon">🔄</span>\n <span class="status-count">${s.in_progress}</span>\n <span class="status-label">Active</span>\n </div>\n <div class="status-item pending">\n <span class="status-icon">⏳</span>\n <span class="status-count">${s.pending}</span>\n <span class="status-label">Pending</span>\n </div>\n </div>\n `,t+='\n <div class="todo-list-primary">\n ',n.forEach((s,a)=>{const n=this.getCheckboxIcon(s.status),e="in_progress"===s.status&&s.activeForm||s.content,i=this.formatStatusClass(s.status);t+=`\n <div class="todo-item ${s.status}">\n <span class="todo-icon ${i}">${n}</span>\n <span class="todo-text">${this.escapeHtml(e)}</span>\n ${"in_progress"===s.status?'<span class="todo-badge active">ACTIVE</span>':""}\n </div>\n `}),t+="\n </div>\n "}else t+='\n <div class="detail-row">\n <span class="detail-value">No todos in list</span>\n </div>\n ';s.callCount&&s.callCount>1&&(t+=`\n <div class="detail-row">\n <span class="detail-label">Updates:</span>\n <span class="detail-value">${s.callCount}</span>\n </div>\n `),t+=this.createCollapsibleJSON(s,"Full Details"),t+="</div>",this.container.innerHTML=t}displayTodo(s){let a;a=s.todos&&Array.isArray(s.todos)?s.todos:Array.isArray(s)?s:s.content&&s.activeForm&&s.status?[s]:[];let n='\n <div class="unified-viewer-header">\n <h6>📋 Todo List</h6>\n </div>\n <div class="unified-viewer-content">\n ';a.length>0?(n+='\n <div class="todo-list-primary">\n ',a.forEach(s=>{const a=this.getCheckboxIcon(s.status),t="in_progress"===s.status&&s.activeForm||s.content,e=this.formatStatusClass(s.status);n+=`\n <div class="todo-item ${s.status}">\n <span class="todo-icon ${e}">${a}</span>\n <span class="todo-text">${this.escapeHtml(t)}</span>\n <span class="todo-status-text ${e}">${s.status.replace("_"," ")}</span>\n </div>\n `}),n+="\n </div>\n "):n+='\n <div class="detail-section">\n <div class="no-todos">No todo items found</div>\n </div>\n ',n+="</div>",this.container.innerHTML=n}displayInstruction(s){let a=`\n <div class="unified-viewer-header">\n <h6>💬 User Instruction</h6>\n <span class="unified-viewer-timestamp">${this.formatTimestamp(s.timestamp)}</span>\n </div>\n <div class="unified-viewer-content">\n `;a+=`\n <div class="primary-data">\n <div class="instruction-content">\n ${this.escapeHtml(s.text)}\n </div>\n <div class="instruction-meta">\n <span class="meta-item">📏 ${s.text.length} characters</span>\n <span class="meta-item">🕐 ${this.formatTimestamp(s.timestamp)}</span>\n </div>\n </div>\n `,Object.keys(s).length>3&&(a+=this.createCollapsibleJSON(s,"Full Instruction Data")),a+="</div>",this.container.innerHTML=a}displaySession(s){let a=`\n <div class="unified-viewer-header">\n <h6>🎯 Session: ${s.session_id||s.id}</h6>\n <span class="unified-viewer-status">${this.formatStatus(s.status||"active")}</span>\n </div>\n <div class="unified-viewer-content">\n <div class="detail-row">\n <span class="detail-label">Session ID:</span>\n <span class="detail-value">${s.session_id||s.id}</span>\n </div>\n <div class="detail-row">\n <span class="detail-label">Start Time:</span>\n <span class="detail-value">${this.formatTimestamp(s.startTime||s.timestamp)}</span>\n </div>\n `;s.working_directory&&(a+=`\n <div class="detail-row">\n <span class="detail-label">Working Directory:</span>\n <span class="detail-value">${s.working_directory}</span>\n </div>\n `),s.git_branch&&(a+=`\n <div class="detail-row">\n <span class="detail-label">Git Branch:</span>\n <span class="detail-value">${s.git_branch}</span>\n </div>\n `),void 0!==s.eventCount&&(a+=`\n <div class="detail-row">\n <span class="detail-label">Events:</span>\n <span class="detail-value">${s.eventCount}</span>\n </div>\n `),a+="</div>",this.container.innerHTML=a}displayFileOperation(s){let a=`\n <div class="unified-viewer-header">\n <h6>📄 File: ${s.file_path}</h6>\n <span class="unified-viewer-count">${s.operations?s.operations.length:1} operation${s.operations&&1!==s.operations.length?"s":""}</span>\n </div>\n <div class="unified-viewer-content">\n <div class="detail-row">\n <span class="detail-label">File Path:</span>\n <span class="detail-value">${s.file_path}</span>\n </div>\n `;s.operations&&Array.isArray(s.operations)&&(a+=`\n <div class="detail-section">\n <span class="detail-section-title">Operations:</span>\n <div class="operations-list">\n ${s.operations.map(s=>`\n <div class="operation-item">\n <span class="operation-type">${s.operation}</span>\n <span class="operation-timestamp">${this.formatTimestamp(s.timestamp)}</span>\n </div>\n `).join("")}\n </div>\n </div>\n `),a+="</div>",this.container.innerHTML=a}displayHook(s){let a=`\n <div class="unified-viewer-header">\n <h6>🔗 Hook: ${s.event_type||s.subtype||"unknown"}</h6>\n <span class="unified-viewer-timestamp">${this.formatTimestamp(s.timestamp)}</span>\n </div>\n <div class="unified-viewer-content">\n `;a+=this.formatHookDetails(s),a+="</div>",this.container.innerHTML=a}displayGeneric(s){let a=`\n <div class="unified-viewer-header">\n <h6>📊 Data Details</h6>\n ${s.timestamp?`<span class="unified-viewer-timestamp">${this.formatTimestamp(s.timestamp)}</span>`:""}\n </div>\n <div class="unified-viewer-content">\n `;if("object"==typeof s&&null!==s){const n=["id","name","type","status","timestamp","text","content","message"];for(let t of n)if(void 0!==s[t]){let n=s[t];"string"==typeof n&&n.length>200&&(n=n.substring(0,200)+"..."),a+=`\n <div class="detail-row">\n <span class="detail-label">${t}:</span>\n <span class="detail-value">${this.escapeHtml(String(n))}</span>\n </div>\n `}}else a+=`<div class="simple-value">${this.escapeHtml(String(s))}</div>`;a+="</div>",this.container.innerHTML=a}formatEventType(s){return s.type&&s.subtype?s.type===s.subtype||"generic"===s.subtype?s.type:`${s.type}.${s.subtype}`:s.type?s.type:s.hook_event_name?s.hook_event_name:"unknown"}formatEventDetails(s){switch(s.data,s.type){case"hook":return this.formatHookDetails(s);case"agent":return this.formatAgentEventDetails(s);case"todo":return this.formatTodoEventDetails(s);case"session":return this.formatSessionEventDetails(s);default:return this.formatGenericEventDetails(s)}}formatHookDetails(s){const a=s.data||{},n=s.subtype||s.event_type||"unknown";let t=`\n <div class="detail-row">\n <span class="detail-label">Hook Type:</span>\n <span class="detail-value">${n}</span>\n </div>\n `;switch(n){case"user_prompt":const s=a.prompt_text||a.prompt_preview||"";t+=`\n <div class="detail-row">\n <span class="detail-label">Prompt:</span>\n <div class="detail-value prompt-text">${this.escapeHtml(s)}</div>\n </div>\n `;break;case"pre_tool":case"post_tool":t+=`\n <div class="detail-row">\n <span class="detail-label">Tool:</span>\n <span class="detail-value">${a.tool_name||"Unknown tool"}</span>\n </div>\n `,a.operation_type&&(t+=`\n <div class="detail-row">\n <span class="detail-label">Operation:</span>\n <span class="detail-value">${a.operation_type}</span>\n </div>\n `),"post_tool"===n&&a.duration_ms&&(t+=`\n <div class="detail-row">\n <span class="detail-label">Duration:</span>\n <span class="detail-value">${a.duration_ms}ms</span>\n </div>\n `);break;case"subagent_start":case"subagent_stop":t+=`\n <div class="detail-row">\n <span class="detail-label">Agent:</span>\n <span class="detail-value">${a.agent_type||a.agent||"Unknown"}</span>\n </div>\n `,"subagent_start"===n&&a.prompt&&(t+=`\n <div class="detail-row">\n <span class="detail-label">Task:</span>\n <div class="detail-value">${this.escapeHtml(a.prompt)}</div>\n </div>\n `),"subagent_stop"===n&&a.reason&&(t+=`\n <div class="detail-row">\n <span class="detail-label">Reason:</span>\n <span class="detail-value">${a.reason}</span>\n </div>\n `)}return t}formatAgentEventDetails(s){const a=s.data||{};let n="";return(a.agent_type||a.name)&&(n+=`\n <div class="detail-row">\n <span class="detail-label">Agent Type:</span>\n <span class="detail-value">${a.agent_type||a.name}</span>\n </div>\n `),s.subtype&&(n+=`\n <div class="detail-row">\n <span class="detail-label">Action:</span>\n <span class="detail-value">${s.subtype}</span>\n </div>\n `),n}formatTodoEventDetails(s){const a=s.data||{};let n="";if(a.todos&&Array.isArray(a.todos)){const s=this.getTodoStatusCounts(a.todos);n+=`\n <div class="detail-row">\n <span class="detail-label">Todo Items:</span>\n <span class="detail-value">${a.todos.length} total</span>\n </div>\n <div class="detail-row">\n <span class="detail-label">Status:</span>\n <span class="detail-value">${s.completed} completed, ${s.in_progress} in progress</span>\n </div>\n `}return n}formatSessionEventDetails(s){const a=s.data||{};let n="";return a.session_id&&(n+=`\n <div class="detail-row">\n <span class="detail-label">Session ID:</span>\n <span class="detail-value">${a.session_id}</span>\n </div>\n `),s.subtype&&(n+=`\n <div class="detail-row">\n <span class="detail-label">Action:</span>\n <span class="detail-value">${s.subtype}</span>\n </div>\n `),n}formatGenericEventDetails(s){const a=s.data||{};let n="";const t=["message","description","value","result"];for(let e of t)if(void 0!==a[e]){let s=a[e];"string"==typeof s&&s.length>200&&(s=s.substring(0,200)+"..."),n+=`\n <div class="detail-row">\n <span class="detail-label">${e}:</span>\n <span class="detail-value">${this.escapeHtml(String(s))}</span>\n </div>\n `}return n}formatEventData(s){const a=s.data;return a&&0!==Object.keys(a).length?`\n <div class="detail-section">\n <span class="detail-section-title">Event Data:</span>\n <pre class="event-data-json">${this.escapeHtml(JSON.stringify(a,null,2))}</pre>\n </div>\n `:""}formatParameters(s,a="Parameters"){if(!s||0===Object.keys(s).length)return`\n <div class="detail-section">\n <span class="detail-section-title">${a}:</span>\n <div class="no-params">No parameters</div>\n </div>\n `;const n=Object.keys(s);return`\n <div class="detail-section">\n <span class="detail-section-title">${a} (${n.length}):</span>\n <div class="params-list">\n ${n.map(a=>{const n=s[a];return`\n <div class="param-item">\n <div class="param-key">${a}:</div>\n <div class="param-value">${this.formatParameterValue(n)}</div>\n </div>\n `}).join("")}\n </div>\n </div>\n `}formatParameterValue(s){if("string"==typeof s)return s.length>500?`<pre class="param-text-long">${this.escapeHtml(s.substring(0,500)+"...\n\n[Content truncated - "+s.length+" total characters]")}</pre>`:s.length>100?`<pre class="param-text">${this.escapeHtml(s)}</pre>`:`<span class="param-text-short">${this.escapeHtml(s)}</span>`;if("object"!=typeof s||null===s)return`<span class="param-primitive">${this.escapeHtml(String(s))}</span>`;if(Array.isArray(s)&&s.length>0&&s[0].hasOwnProperty("content")&&s[0].hasOwnProperty("status"))return this.formatTodosAsParameter(s);try{return`<pre class="param-json">${this.escapeHtml(JSON.stringify(s,null,2))}</pre>`}catch(a){return'<span class="param-error">Error displaying object</span>'}}formatTodosAsParameter(s){const a=this.getTodoStatusCounts(s);let n=`\n <div class="param-todos">\n <div class="param-todos-header">\n Array of todo objects (${s.length} items)\n </div>\n <div class="param-todos-summary">\n ${a.completed} completed • ${a.in_progress} in progress • ${a.pending} pending\n </div>\n <div class="param-todos-list">\n `;return s.forEach((s,a)=>{const t=this.getCheckboxIcon(s.status),e="in_progress"===s.status&&s.activeForm||s.content,i=this.formatStatusClass(s.status);n+=`\n <div class="param-todo-item ${s.status}">\n <div class="param-todo-checkbox">\n <span class="param-checkbox-icon ${i}">${t}</span>\n </div>\n <div class="param-todo-text">\n <span class="param-todo-content">${this.escapeHtml(e)}</span>\n <span class="param-todo-status-badge ${i}">${s.status.replace("_"," ")}</span>\n </div>\n </div>\n `}),n+="\n </div>\n </div>\n ",n}formatTimestamp(s){if(!s)return"Unknown time";try{const a=new Date(s);return isNaN(a.getTime())?"Invalid date":a.toLocaleString()}catch(a){return"Invalid date"}}formatStatus(s){if(!s)return"unknown";return{active:"🟢 Active",completed:"✅ Completed",in_progress:"🔄 In Progress",pending:"⏳ Pending",error:"❌ Error",failed:"❌ Failed"}[s]||s}formatStatusClass(s){return`status-${s}`}getAgentIcon(s){return{PM:"🎯",Engineer:"🔧","Engineer Agent":"🔧",Research:"🔍","Research Agent":"🔍",QA:"✅","QA Agent":"✅",Architect:"🏗️","Architect Agent":"🏗️",Ops:"⚙️","Ops Agent":"⚙️"}[s]||"🤖"}getToolIcon(s){return{Read:"👁️",Write:"✍️",Edit:"✏️",MultiEdit:"📝",Bash:"💻",Grep:"🔍",Glob:"📂",LS:"📁",TodoWrite:"📝",Task:"📋",WebFetch:"🌐"}[s]||"🔧"}getCheckboxIcon(s){return{pending:"⏳",in_progress:"🔄",completed:"✅"}[s]||"❓"}getTodoStatusCounts(s){const a={completed:0,in_progress:0,pending:0};return s.forEach(s=>{a.hasOwnProperty(s.status)&&a[s.status]++}),a}escapeHtml(s){if("string"!=typeof s)return"";const a=document.createElement("div");return a.textContent=s,a.innerHTML}createCollapsibleJSON(s,a="Full Details"){const n=`json-details-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,t=this.cleanDataForDisplay(s);return`\n <div class="collapsible-json-section">\n <button class="collapsible-json-toggle" onclick="\n const content = document.getElementById('${n}');\n const button = this;\n if (content.style.display === 'none' || content.style.display === '') {\n content.style.display = 'block';\n button.classList.add('expanded');\n button.innerHTML = '▼ ${a}';\n } else {\n content.style.display = 'none';\n button.classList.remove('expanded');\n button.innerHTML = '▶ ${a}';\n }\n ">▶ ${a}</button>\n <div id="${n}" class="collapsible-json-content" style="display: none;">\n <pre class="json-viewer">${this.escapeHtml(JSON.stringify(t,null,2))}</pre>\n </div>\n </div>\n `}cleanDataForDisplay(s){const a=new WeakSet;return JSON.parse(JSON.stringify(s,(s,n)=>{if("object"==typeof n&&null!==n){if(a.has(n))return"[Circular Reference]";a.add(n)}return"string"==typeof n&&n.length>1e3?n.substring(0,1e3)+"... [truncated]":"function"==typeof n?"[Function]":n}))}clear(){this.container&&(this.container.innerHTML=""),this.currentData=null,this.currentType=null}getCurrentData(){return this.currentData}getCurrentType(){return this.currentType}hasData(){return null!==this.currentData}}window.UnifiedDataViewer=s;export{s as U};
2
+ //# sourceMappingURL=unified-data-viewer.CvAmgM3l.js.map
@@ -1,2 +1,2 @@
1
- class e{constructor(){this.container=null,this.events=[],this.sessions=new Map,this.currentSession=null,this.selectedSessionFilter="all",this.timeRange="30min",this.searchTerm="",this.initialized=!1,this.expandedSessions=new Set,this.expandedAgents=new Set,this.expandedTools=new Set,this.selectedItem=null}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");const e=document.getElementById("activity-tab");if(e){if(!e.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.setupControls(),this.subscribeToEvents(),void(this.initialized=!0);this.setupControls(),this.createLinearTreeView(),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}forceShow(){console.log("ActivityTree.forceShow() called"),this.container||(this.container=document.getElementById("activity-tree-container")||document.getElementById("activity-tree"),this.container)?(this.createLinearTreeView(),this.renderTree()):console.error("Cannot find activity tree container")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.createLinearTreeView(),this.renderTree()}setupControls(){const e=document.getElementById("time-range");e&&e.addEventListener("change",e=>{this.timeRange=e.target.value,console.log(`ActivityTree: Time range changed to: ${this.timeRange}`),this.renderTree()}),document.addEventListener("sessionFilterChanged",e=>{this.selectedSessionFilter=e.detail.sessionId||"all",console.log(`ActivityTree: Session filter changed to: ${this.selectedSessionFilter} (from SessionManager)`),this.renderTree()}),document.addEventListener("sessionChanged",e=>{this.selectedSessionFilter=e.detail.sessionId||"all",console.log(`ActivityTree: Session changed to: ${this.selectedSessionFilter} (from SessionManager - backward compat)`),this.renderTree()}),setTimeout(()=>{if(window.sessionManager){const e=window.sessionManager.getCurrentFilter();e!==this.selectedSessionFilter&&(this.selectedSessionFilter=e||"all",console.log(`ActivityTree: Initialized with current session filter: ${this.selectedSessionFilter}`),this.renderTree())}},100);const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAllSessions());const s=document.getElementById("collapse-all");s&&s.addEventListener("click",()=>this.collapseAllSessions());const n=document.getElementById("reset-zoom");n&&(n.style.display="inline-block",n.addEventListener("click",()=>this.resetZoom()));const i=document.getElementById("activity-search");i&&i.addEventListener("input",e=>{this.searchTerm=e.target.value.toLowerCase(),this.renderTree()})}createLinearTreeView(){console.log("Creating linear tree view"),this.container.innerHTML="";const e=document.createElement("div");e.id="linear-tree",e.className="linear-tree",this.container.appendChild(e),console.log("Linear tree view created")}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((e,t)=>{console.log(`ActivityTree: onEventUpdate called with ${e.length} total events and ${t.size} sessions`),this.sessions.clear();for(const[n,i]of t.entries()){const e={id:n,timestamp:new Date(i.lastActivity||i.startTime||new Date),expanded:this.expandedSessions.has(n)||!0,agents:new Map,todos:[],userInstructions:[],tools:[],status:"active",currentTodoTool:null,working_directory:i.working_directory,git_branch:i.git_branch,eventCount:i.eventCount};this.sessions.set(n,e)}const s=e.length-this.events.length;if(s>0){const t=e.slice(this.events.length);console.log(`ActivityTree: Processing ${s} new events`,t),t.forEach(e=>{this.processEvent(e)})}this.events=[...e],this.renderTree(),console.log("ActivityTree: Sessions after sync with socket client:",Array.from(this.sessions.entries()))});const e=window.socketClient?.getState();if(e&&e.events.length>0){console.log(`ActivityTree: Loading existing data - ${e.events.length} events, ${e.sessions.size} sessions`),this.sessions.clear();for(const[t,s]of e.sessions.entries()){const e={id:t,timestamp:new Date(s.lastActivity||s.startTime||new Date),expanded:this.expandedSessions.has(t)||!0,agents:new Map,todos:[],userInstructions:[],tools:[],status:"active",currentTodoTool:null,working_directory:s.working_directory,git_branch:s.git_branch,eventCount:s.eventCount};this.sessions.set(t,e)}e.events.forEach(e=>{this.processEvent(e)}),this.events=[...e.events],this.renderTree(),console.log("ActivityTree: Initial sessions state:",Array.from(this.sessions.entries()))}else console.log("ActivityTree: No existing events found"),this.events=[],this.sessions.clear(),this.renderTree()}processEvent(e){if(!e)return void console.log("ActivityTree: Ignoring null event");let t,s=this.getEventType(e);if(!s)return;console.log(`ActivityTree: Processing event: ${s}`,e),e.timestamp?(t=new Date(e.timestamp),isNaN(t.getTime())&&(console.warn("ActivityTree: Invalid timestamp, using current time:",e.timestamp),t=new Date)):(console.warn("ActivityTree: No timestamp found, using current time"),t=new Date);const n=e.session_id||e.data?.session_id;if(!n)return void console.log(`ActivityTree: Skipping event without session_id: ${s}`);if(!this.sessions.has(n))return void console.warn(`ActivityTree: Session ${n} not found in authoritative sessions - skipping event`);const i=this.sessions.get(n);switch(s){case"Start":this.currentSession=i;break;case"user_prompt":this.processUserInstruction(e,i);break;case"TodoWrite":this.processTodoWrite(e,i);break;case"SubagentStart":this.processSubagentStart(e,i);break;case"SubagentStop":this.processSubagentStop(e,i);break;case"PreToolUse":this.processToolUse(e,i);break;case"PostToolUse":this.updateToolStatus(e,i,"completed")}this.updateStats()}getEventType(e){if(e.hook_event_name)return e.hook_event_name;if("hook"===e.type&&e.subtype){return{pre_tool:"PreToolUse",post_tool:"PostToolUse",subagent_start:"SubagentStart",subagent_stop:"SubagentStop",todo_write:"TodoWrite"}[e.subtype]}if("todo"===e.type&&"updated"===e.subtype)return"TodoWrite";if("subagent"===e.type){if("started"===e.subtype)return"SubagentStart";if("stopped"===e.subtype)return"SubagentStop"}return"start"===e.type?"Start":"user_prompt"===e.type||"user_prompt"===e.subtype?"user_prompt":null}processUserInstruction(e,t){const s=e.prompt_text||e.data?.prompt_text||e.prompt||"";if(!s)return;const n={id:`instruction-${t.id}-${Date.now()}`,text:s,preview:s.length>100?s.substring(0,100)+"...":s,timestamp:e.timestamp||(new Date).toISOString(),type:"user_instruction"};t.userInstructions.push(n),t.userInstructions.length>5&&(t.userInstructions=t.userInstructions.slice(-5))}processTodoWrite(e,t){let s=e.todos||e.data?.todos||e.data||[];if(s&&"object"==typeof s&&s.todos&&(s=s.todos),!Array.isArray(s)||0===s.length)return;t.todos=s.map(t=>({content:t.content,activeForm:t.activeForm,status:t.status,timestamp:e.timestamp}));const n={id:`todo-session-${t.id}-${Date.now()}`,name:"TodoWrite",type:"tool",icon:"📝",timestamp:e.timestamp,status:"active",params:{todos:s},isPrioritizedTool:!0};t.tools=t.tools.filter(e=>"TodoWrite"!==e.name),t.tools.unshift(n),t.currentTodoTool=n;const i=e.session_id||e.data?.session_id;let a=null;if(i&&t.agents.has(i))a=t.agents.get(i);else{const e=Array.from(t.agents.values()).filter(e=>"active"===e.status||"in_progress"===e.status).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));if(e.length>0)a=e[0];else{const e=Array.from(t.agents.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));e.length>0&&(a=e[0])}}if(a){const t={id:`todo-agent-${a.id}-${Date.now()}`,name:"TodoWrite",type:"tool",icon:"📝",timestamp:e.timestamp,status:"active",params:{todos:s},isPrioritizedTool:!0};a.tools=a.tools.filter(e=>"TodoWrite"!==e.name),a.tools.unshift(t)}}processSubagentStart(e,t){const s=e.agent_name||e.data?.agent_name||e.data?.agent_type||e.agent_type||e.agent||"unknown",n=e.session_id||e.data?.session_id,i=n||`agent-${Date.now()}-${Math.random()}`;if(t.agents.has(i)){const s=t.agents.get(i);s.status="active",s.timestamp=e.timestamp}else{const a={id:i,name:s,type:"agent",icon:this.getAgentIcon(s),timestamp:e.timestamp,status:"active",tools:[],sessionId:n,isPM:!1};t.agents.set(i,a)}}processSubagentStop(e,t){const s=e.session_id||e.data?.session_id;if(s&&t.agents.has(s)){t.agents.get(s).status="completed"}}processToolUse(e,t){const s=e.tool_name||e.data?.tool_name||e.tool||e.data?.tool||"unknown",n=e.tool_parameters||e.data?.tool_parameters||e.parameters||e.data?.parameters||{},i=e.session_id||e.data?.session_id,a={id:`tool-${Date.now()}-${Math.random()}`,name:s,type:"tool",icon:this.getToolIcon(s),timestamp:e.timestamp,status:"in_progress",params:n,eventId:e.id};let o=null;if(i&&t.agents.has(i))o=t.agents.get(i);else{const e=Array.from(t.agents.values()).filter(e=>"active"===e.status).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));if(!(e.length>0))return void t.tools.push(a);o=e[0]}o&&o.tools.push(a)}updateToolStatus(e,t,s){const n=t=>{if(t.tools){const n=t.tools.find(t=>t.eventId===e.id);if(n)return n.status=s,!0}return!1};for(let i of t.agents.values())if(n(i))return;!t.tools||n(t)}renderTree(){const e=document.getElementById("linear-tree");if(!e)return;e.innerHTML="";const t=Array.from(this.sessions.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));for(let s of t){if("all"!==this.selectedSessionFilter&&this.selectedSessionFilter!==s.id)continue;const t=this.createSessionElement(s);e.appendChild(t)}}createSessionElement(e){const t=this.expandedSessions.has(e.id)||e.expanded;let s;try{const t=e.timestamp instanceof Date?e.timestamp:new Date(e.timestamp);isNaN(t.getTime())?(s="Invalid Date",console.warn("ActivityTree: Invalid session timestamp:",e.timestamp)):s=t.toLocaleString()}catch(l){s="Invalid Date",console.error("ActivityTree: Error formatting session timestamp:",l,e.timestamp)}const n=document.createElement("div");n.className="tree-node session",n.dataset.sessionId=e.id;const i=t?"▼":"▶",a=e.agents?e.agents.size:0,o=e.todos?e.todos.length:0,r=e.userInstructions?e.userInstructions.length:0;return console.log(`ActivityTree: Rendering session ${e.id}: ${a} agents, ${r} instructions, ${o} todos at ${s}`),n.innerHTML=`\n <div class="tree-node-content" onclick="window.activityTreeInstance.toggleSession('${e.id}')">\n <span class="tree-expand-icon">${i}</span>\n <span class="tree-icon">🎯</span>\n <span class="tree-label">PM Session</span>\n <span class="tree-meta">${s} • ${a} agent(s) • ${r} instruction(s) • ${o} todo(s)</span>\n </div>\n <div class="tree-children" style="display: ${t?"block":"none"}">\n ${this.renderSessionContent(e)}\n </div>\n `,n}renderSessionContent(e){let t="";if(e.userInstructions&&e.userInstructions.length>0)for(let n of e.userInstructions.slice(-3))t+=this.renderUserInstructionElement(n,1);if(e.todos&&e.todos.length>0&&(t+=this.renderTodoChecklistElement(e.todos,1)),e.tools&&e.tools.length>0)for(let n of e.tools)t+=this.renderToolElement(n,1);const s=Array.from(e.agents.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));for(let n of s)t+=this.renderAgentElement(n,1);return t}renderUserInstructionElement(e,t){return`\n <div class="tree-node user-instruction ${this.selectedItem&&"instruction"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":""}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">💬</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'instruction', event)">User: "${this.escapeHtml(e.preview)}"</span>\n <span class="tree-status status-active">instruction</span>\n </div>\n </div>\n `}renderTodoChecklistElement(e,t){const s=`checklist-${Date.now()}`,n=!1!==this.expandedTools.has(s),i=n?"▼":"▶";let a=0,o=0;e.forEach(e=>{"completed"===e.status?a++:"in_progress"===e.status&&o++});let r="";r=o>0?`${o} in progress, ${a} completed`:a===e.length&&e.length>0?`All ${e.length} completed`:`${e.length} todo(s)`;let l=`\n <div class="tree-node todo-checklist" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoChecklist('${s}'); event.stopPropagation();">${i}</span>\n <span class="tree-icon">☑️</span>\n <span class="tree-label">TODOs</span>\n <span class="tree-params">${r}</span>\n <span class="tree-status status-active">checklist</span>\n </div>\n `;if(n){l+='<div class="tree-children">';for(let s of e){const e=this.getCheckboxIcon(s.status),n=`status-${s.status}`,i="in_progress"===s.status?s.activeForm:s.content;l+=`\n <div class="tree-node todo-item ${n}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${e}</span>\n <span class="tree-label">${this.escapeHtml(i)}</span>\n <span class="tree-status ${n}">${s.status.replace("_"," ")}</span>\n </div>\n </div>\n `}l+="</div>"}return l+="</div>",l}renderAgentElement(e,t){const s="active"===e.status?"status-active":"status-completed",n=this.expandedAgents.has(e.id),i=e.tools&&e.tools.length>0,a=i?n?"▼":"▶":"";let o=`\n <div class="tree-node agent ${s} ${this.selectedItem&&"agent"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":""}" data-level="${t}">\n <div class="tree-node-content">\n ${a?`<span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleAgent('${e.id}'); event.stopPropagation();">${a}</span>`:'<span class="tree-expand-icon"></span>'}\n <span class="tree-icon">${e.icon}</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'agent', event)">${e.name}</span>\n <span class="tree-status ${s}">${e.status}</span>\n </div>\n `;if(i&&n){o+='<div class="tree-children">';for(let s of e.tools)o+=this.renderToolElement(s,t+1);o+="</div>"}return o+="</div>",o}renderToolElement(e,t){const s=`status-${e.status}`,n=this.getToolParams(e);return`\n <div class="tree-node tool ${s} ${this.selectedItem&&"tool"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":""}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${e.icon}</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'tool', event)">${e.name} (click to view details)</span>\n <span class="tree-params">${n}</span>\n <span class="tree-status ${s}">${e.status}</span>\n </div>\n </div>\n `}getToolParams(e){if(!e.params)return"";if("Read"===e.name&&e.params.file_path)return e.params.file_path;if("Edit"===e.name&&e.params.file_path)return e.params.file_path;if("Write"===e.name&&e.params.file_path)return e.params.file_path;if("Bash"===e.name&&e.params.command){const t=e.params.command;return t.length>50?t.substring(0,50)+"...":t}return"WebFetch"===e.name&&e.params.url?e.params.url:""}getStatusIcon(e){return{pending:"⏸️",in_progress:"🔄",completed:"✅"}[e]||"❓"}getCheckboxIcon(e){return{pending:"⏳",in_progress:"🔄",completed:"✅"}[e]||"❓"}getAgentIcon(e){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️"}[e.toLowerCase()]||"🤖"}getToolIcon(e){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[e.toLowerCase()]||"🔧"}toggleSession(e){this.expandedSessions.has(e)?this.expandedSessions.delete(e):this.expandedSessions.add(e);const t=this.sessions.get(e);t&&(t.expanded=this.expandedSessions.has(e)),this.renderTree()}expandAllSessions(){for(let e of this.sessions.keys()){this.expandedSessions.add(e);const t=this.sessions.get(e);t&&(t.expanded=!0)}this.renderTree()}collapseAllSessions(){this.expandedSessions.clear();for(let e of this.sessions.values())e.expanded=!1;this.renderTree()}updateStats(){const e=this.countTotalNodes(),t=this.countActiveNodes(),s=this.calculateMaxDepth(),n=document.getElementById("node-count"),i=document.getElementById("active-count"),a=document.getElementById("tree-depth");n&&(n.textContent=e),i&&(i.textContent=t),a&&(a.textContent=s),console.log(`ActivityTree: Stats updated - Nodes: ${e}, Active: ${t}, Depth: ${s}`)}countTotalNodes(){let e=0;for(let t of this.sessions.values()){e+=1,e+=t.agents.size,t.userInstructions&&(e+=t.userInstructions.length),t.todos&&(e+=t.todos.length),t.tools&&(e+=t.tools.length);for(let s of t.agents.values())s.tools&&(e+=s.tools.length)}return e}countActiveNodes(){let e=0;for(let t of this.sessions.values()){if("active"===t.status&&e++,t.todos)for(let s of t.todos)"in_progress"===s.status&&e++;if(t.tools)for(let s of t.tools)"in_progress"===s.status&&e++;for(let s of t.agents.values())if("active"===s.status&&e++,s.tools)for(let t of s.tools)"in_progress"===t.status&&e++}return e}calculateMaxDepth(){let e=0;for(let t of this.sessions.values()){let s=1;t.userInstructions&&t.userInstructions.length>0&&(s=Math.max(s,2)),t.todos&&t.todos.length>0&&(s=Math.max(s,3)),t.tools&&t.tools.length>0&&(s=Math.max(s,2));for(let e of t.agents.values())e.tools&&e.tools.length>0&&(s=Math.max(s,3));e=Math.max(e,s)}return e}toggleAgent(e){this.expandedAgents.has(e)?this.expandedAgents.delete(e):this.expandedAgents.add(e),this.renderTree()}toggleTool(e){console.log("Tool expansion is disabled. Tools now show data in the left pane when clicked.")}toggleTodoChecklist(e){this.expandedTools.has(e)?this.expandedTools.delete(e):this.expandedTools.add(e),this.renderTree()}selectItem(e,t,s){s&&s.stopPropagation(),this.selectedItem={data:e,type:t},this.displayItemData(e,t),this.renderTree()}displayItemData(e,t){if("tool"===t&&"TodoWrite"===e.name&&e.params&&e.params.todos)return void this.displayTodoWriteData(e);switch(t){case"agent":this.displayAgentData(e);break;case"tool":this.displayToolData(e);break;case"instruction":this.displayInstructionData(e);break;default:this.displayGenericData(e,t)}const s=document.querySelector(".module-data-header h5");if(s){const n={agent:"🤖",tool:"🔧",instruction:"💬",session:"🎯"}[t]||"📊",i=e.name||e.agentName||e.tool_name||"Item";s.textContent=`${n} ${t}: ${i}`}}displayTodoWriteData(e){const t=e.params.todos||[],s=this.formatTimestamp(e.timestamp);let n=0,i=0,a=0;t.forEach(e=>{"completed"===e.status?n++:"in_progress"===e.status?i++:a++});let o=`\n <div class="unified-viewer-header">\n <h6>📝 TodoWrite: PM ${s}</h6>\n <span class="unified-viewer-status">${this.formatStatus(e.status)}</span>\n </div>\n <div class="unified-viewer-content">\n `;t.length>0?(o+=`\n <div class="detail-section">\n <span class="detail-section-title">Todo Summary</span>\n <div class="todo-summary">\n <div class="summary-item completed">\n <span class="summary-icon">✅</span>\n <span class="summary-count">${n}</span>\n <span class="summary-label">Completed</span>\n </div>\n <div class="summary-item in_progress">\n <span class="summary-icon">🔄</span>\n <span class="summary-count">${i}</span>\n <span class="summary-label">In Progress</span>\n </div>\n <div class="summary-item pending">\n <span class="summary-icon">⏳</span>\n <span class="summary-count">${a}</span>\n <span class="summary-label">Pending</span>\n </div>\n </div>\n </div>\n `,o+=`\n <div class="detail-section">\n <span class="detail-section-title">Todo List (${t.length} items)</span>\n <div class="todo-checklist">\n `,t.forEach((e,t)=>{const s=this.getCheckboxIcon(e.status),n="in_progress"===e.status&&e.activeForm||e.content,i=this.formatStatusClass(e.status);o+=`\n <div class="todo-checklist-item ${e.status}">\n <div class="todo-checkbox">\n <span class="checkbox-icon ${i}">${s}</span>\n </div>\n <div class="todo-text">\n <span class="todo-content">${this.escapeHtml(n)}</span>\n <span class="todo-status-badge ${i}">${e.status.replace("_"," ")}</span>\n </div>\n </div>\n `}),o+="\n </div>\n </div>\n "):o+='\n <div class="detail-section">\n <div class="no-todos">No todo items found</div>\n </div>\n ',o+=`\n <div class="detail-section">\n <span class="detail-section-title">Parameters (${Object.keys(e.params).length})</span>\n <div class="params-list">\n <div class="param-item">\n <div class="param-key">todos:</div>\n <div class="param-value">\n <pre class="param-json">${this.escapeHtml(JSON.stringify(t,null,2))}</pre>\n </div>\n </div>\n </div>\n </div>\n `,o+="</div>";const r=document.getElementById("module-data-content");r&&(r.innerHTML=o);const l=document.querySelector(".module-data-header h5");l&&(l.textContent="📝 tool: TodoWrite")}formatStatus(e){if(!e)return"unknown";return{active:"🟢 Active",completed:"✅ Completed",in_progress:"🔄 In Progress",pending:"⏳ Pending",error:"❌ Error",failed:"❌ Failed"}[e]||e}formatStatusClass(e){return`status-${e}`}formatTimestamp(e){if(!e)return"";try{const t=new Date(e);return isNaN(t.getTime())?"":t.toLocaleTimeString()}catch(t){return""}}displayAgentData(e){const t=this.formatTimestamp(e.timestamp),s=document.getElementById("module-data-content");if(!s)return;let n=`\n <div class="detail-section">\n <span class="detail-section-title">Agent Information</span>\n <div class="agent-info">\n <div class="info-item">\n <span class="info-label">Name:</span>\n <span class="info-value">${this.escapeHtml(e.name)}</span>\n </div>\n <div class="info-item">\n <span class="info-label">Status:</span>\n <span class="info-value status-${e.status}">${e.status}</span>\n </div>\n <div class="info-item">\n <span class="info-label">Timestamp:</span>\n <span class="info-value">${t}</span>\n </div>\n <div class="info-item">\n <span class="info-label">Session ID:</span>\n <span class="info-value">${e.sessionId||"N/A"}</span>\n </div>\n </div>\n </div>\n `;e.tools&&e.tools.length>0&&(n+=`\n <div class="detail-section">\n <span class="detail-section-title">Tools (${e.tools.length})</span>\n <div class="tool-list">\n `,e.tools.forEach(e=>{n+=`\n <div class="tool-item">\n <span class="tool-name">${this.escapeHtml(e.name)}</span>\n <span class="tool-status status-${e.status}">${e.status}</span>\n </div>\n `}),n+="\n </div>\n </div>\n "),s.innerHTML=n}displayToolData(e){const t=this.formatTimestamp(e.timestamp),s=document.getElementById("module-data-content");if(!s)return;let n=`\n <div class="detail-section">\n <span class="detail-section-title">Tool Information</span>\n <div class="tool-info">\n <div class="info-item">\n <span class="info-label">Name:</span>\n <span class="info-value">${this.escapeHtml(e.name)}</span>\n </div>\n <div class="info-item">\n <span class="info-label">Status:</span>\n <span class="info-value status-${e.status}">${e.status}</span>\n </div>\n <div class="info-item">\n <span class="info-label">Timestamp:</span>\n <span class="info-value">${t}</span>\n </div>\n </div>\n </div>\n `;e.params&&Object.keys(e.params).length>0&&(n+='\n <div class="detail-section">\n <span class="detail-section-title">Parameters</span>\n <div class="params-list">\n ',Object.entries(e.params).forEach(([e,t])=>{n+=`\n <div class="param-item">\n <div class="param-key">${this.escapeHtml(e)}:</div>\n <div class="param-value">${this.escapeHtml(String(t))}</div>\n </div>\n `}),n+="\n </div>\n </div>\n "),s.innerHTML=n}displayInstructionData(e){const t=this.formatTimestamp(e.timestamp),s=document.getElementById("module-data-content");if(!s)return;const n=`\n <div class="detail-section">\n <span class="detail-section-title">User Instruction</span>\n <div class="instruction-info">\n <div class="info-item">\n <span class="info-label">Timestamp:</span>\n <span class="info-value">${t}</span>\n </div>\n <div class="instruction-content">\n <div class="instruction-text">${this.escapeHtml(e.text)}</div>\n </div>\n </div>\n </div>\n `;s.innerHTML=n}displayGenericData(e,t){const s=document.getElementById("module-data-content");if(!s)return;let n=`\n <div class="detail-section">\n <span class="detail-section-title">${t||"Item"} Data</span>\n <div class="generic-data">\n <pre>${this.escapeHtml(JSON.stringify(e,null,2))}</pre>\n </div>\n </div>\n `;s.innerHTML=n}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}resetZoom(){this.svg&&this.zoom&&this.svg.transition().duration(this.duration).call(this.zoom.transform,d3.zoomIdentity)}escapeJson(e){return JSON.stringify(e).replace(/'/g,"&apos;").replace(/"/g,"&quot;")}}window.ActivityTree=e;const t=()=>{let t=null;const s=()=>{t||(console.log("Creating new Activity Tree instance..."),t=new e,window.activityTreeInstance=t,window.activityTree=()=>t),setTimeout(()=>{console.log("Attempting to initialize Activity Tree visualization..."),t.initialize()},100)};document.querySelectorAll(".tab-button").forEach(e=>{e.addEventListener("click",e=>{"activity"===e.target.getAttribute("data-tab")&&(console.log("Activity tab button clicked, initializing tree..."),s(),t&&setTimeout(()=>{t.renderWhenVisible(),t.forceShow()},150))})}),document.addEventListener("tabChanged",e=>{e.detail&&"activity"===e.detail.newTab&&(console.log("Tab changed to activity, initializing tree..."),s(),t&&setTimeout(()=>{t.renderWhenVisible(),t.forceShow()},150))});const n=document.querySelector(".tab-button.active");n&&"activity"===n.getAttribute("data-tab")&&(console.log("Activity tab is active on load, initializing tree..."),s());const i=document.getElementById("activity-tab");i&&i.classList.contains("active")&&(console.log("Activity panel is active on load, initializing tree..."),t||s())};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",t):t();
1
+ import{U as e}from"../chunks/unified-data-viewer.CvAmgM3l.js";class t{constructor(){this.container=null,this.events=[],this.processedEventIds=new Set,this.sessions=new Map,this.currentSession=null,this.selectedSessionFilter="all",this.timeRange="30min",this.searchTerm="",this.initialized=!1,this.expandedSessions=new Set,this.expandedAgents=new Set,this.expandedTools=new Set,this.selectedItem=null,this.renderTreeDebounced=this.debounce(()=>this.renderTree(),100)}debounce(e,t){let s;return function(...n){clearTimeout(s),s=setTimeout(()=>{clearTimeout(s),e(...n)},t)}}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");const e=document.getElementById("activity-tab");if(e){if(!e.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.setupControls(),this.subscribeToEvents(),void(this.initialized=!0);this.setupControls(),this.createLinearTreeView(),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}forceShow(){console.log("ActivityTree.forceShow() called"),this.container||(this.container=document.getElementById("activity-tree-container")||document.getElementById("activity-tree"),this.container)?(this.createLinearTreeView(),this.renderTree()):console.error("Cannot find activity tree container")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.createLinearTreeView(),this.renderTree()}setupControls(){const e=document.getElementById("time-range");e&&e.addEventListener("change",e=>{this.timeRange=e.target.value,console.log(`ActivityTree: Time range changed to: ${this.timeRange}`),this.renderTree()}),document.addEventListener("sessionFilterChanged",e=>{this.selectedSessionFilter=e.detail.sessionId||"all",console.log(`ActivityTree: Session filter changed to: ${this.selectedSessionFilter} (from SessionManager)`),this.renderTree()}),document.addEventListener("sessionChanged",e=>{this.selectedSessionFilter=e.detail.sessionId||"all",console.log(`ActivityTree: Session changed to: ${this.selectedSessionFilter} (from SessionManager - backward compat)`),this.renderTree()}),setTimeout(()=>{if(window.sessionManager){const e=window.sessionManager.getCurrentFilter();e!==this.selectedSessionFilter&&(this.selectedSessionFilter=e||"all",console.log(`ActivityTree: Initialized with current session filter: ${this.selectedSessionFilter}`),this.renderTree())}},100);const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAllSessions());const s=document.getElementById("collapse-all");s&&s.addEventListener("click",()=>this.collapseAllSessions());const n=document.getElementById("reset-zoom");n&&(n.style.display="inline-block",n.addEventListener("click",()=>this.resetZoom()));const o=document.getElementById("activity-search");o&&o.addEventListener("input",e=>{this.searchTerm=e.target.value.toLowerCase(),this.renderTree()})}createLinearTreeView(){console.log("Creating linear tree view"),this.container.innerHTML="";const e=document.createElement("div");e.id="linear-tree",e.className="linear-tree",this.container.appendChild(e),console.log("Linear tree view created")}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((e,t)=>{console.log(`ActivityTree: onEventUpdate called with ${e.length} total events and ${t.size} sessions`);for(const[n,o]of t.entries())if(this.sessions.has(n)){const e=this.sessions.get(n);e.timestamp=new Date(o.lastActivity||o.startTime||e.timestamp),e.eventCount=o.eventCount,e.status=o.status||e.status,e.working_directory=o.working_directory||e.working_directory,e.git_branch=o.git_branch||e.git_branch}else{const e={id:n,timestamp:new Date(o.lastActivity||o.startTime||new Date),expanded:this.expandedSessions.has(n)||!0,agents:new Map,todos:[],userInstructions:[],tools:[],toolsMap:new Map,status:"active",currentTodoTool:null,working_directory:o.working_directory,git_branch:o.git_branch,eventCount:o.eventCount};this.sessions.set(n,e)}const s=e.filter(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;return!this.processedEventIds.has(t)});s.length>0&&(console.log(`ActivityTree: Processing ${s.length} new events`,s),s.forEach(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;this.processedEventIds.add(t),this.processEvent(e)})),this.events=[...e],this.renderTreeDebounced(),console.log("ActivityTree: Sessions after sync with socket client:",Array.from(this.sessions.entries()))});const e=window.socketClient?.getState();if(e&&e.events.length>0){console.log(`ActivityTree: Loading existing data - ${e.events.length} events, ${e.sessions.size} sessions`);for(const[s,n]of e.sessions.entries())if(!this.sessions.has(s)){const e={id:s,timestamp:new Date(n.lastActivity||n.startTime||new Date),expanded:this.expandedSessions.has(s)||!0,agents:new Map,todos:[],userInstructions:[],tools:[],toolsMap:new Map,status:"active",currentTodoTool:null,working_directory:n.working_directory,git_branch:n.git_branch,eventCount:n.eventCount};this.sessions.set(s,e)}const t=e.events.filter(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;return!this.processedEventIds.has(t)});t.length>0&&(console.log(`ActivityTree: Processing ${t.length} unprocessed events from initial load`),t.forEach(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;this.processedEventIds.add(t),this.processEvent(e)})),this.events=[...e.events],this.renderTree(),console.log("ActivityTree: Initial sessions state:",Array.from(this.sessions.entries()))}else console.log("ActivityTree: No existing events found"),this.events=[],this.sessions.clear(),this.renderTree()}processEvent(e){if(!e)return void console.log("ActivityTree: Ignoring null event");let t,s=this.getEventType(e);if(!s)return;console.log(`ActivityTree: Processing event: ${s}`,e),e.timestamp?(t=new Date(e.timestamp),isNaN(t.getTime())&&(console.warn("ActivityTree: Invalid timestamp, using current time:",e.timestamp),t=new Date)):(console.warn("ActivityTree: No timestamp found, using current time"),t=new Date);const n=e.session_id||e.data?.session_id;if(!n)return void console.log(`ActivityTree: Skipping event without session_id: ${s}`);if(!this.sessions.has(n))return void console.warn(`ActivityTree: Session ${n} not found in authoritative sessions - skipping event`);const o=this.sessions.get(n);switch(s){case"Start":this.currentSession=o;break;case"user_prompt":this.processUserInstruction(e,o);break;case"TodoWrite":break;case"SubagentStart":this.processSubagentStart(e,o);break;case"SubagentStop":this.processSubagentStop(e,o);break;case"PreToolUse":this.processToolUse(e,o);break;case"PostToolUse":this.updateToolStatus(e,o,"completed")}this.updateStats()}getEventType(e){if(e.hook_event_name)return e.hook_event_name;if("hook"===e.type&&e.subtype){return{pre_tool:"PreToolUse",post_tool:"PostToolUse",subagent_start:"SubagentStart",subagent_stop:"SubagentStop",todo_write:"TodoWrite"}[e.subtype]}if("todo"===e.type&&"updated"===e.subtype)return"TodoWrite";if("subagent"===e.type){if("started"===e.subtype)return"SubagentStart";if("stopped"===e.subtype)return"SubagentStop"}return"start"===e.type?"Start":"user_prompt"===e.type||"user_prompt"===e.subtype?"user_prompt":null}processUserInstruction(e,t){const s=e.prompt_text||e.data?.prompt_text||e.prompt||"";if(!s)return;const n={id:`instruction-${t.id}-${Date.now()}`,text:s,preview:s.length>100?s.substring(0,100)+"...":s,timestamp:e.timestamp||(new Date).toISOString(),type:"user_instruction"};if(t.agents.size>0){console.log("ActivityTree: New user prompt detected, collapsing previous agents");for(let e of t.agents.values())"active"===e.status&&(e.status="completed"),this.expandedAgents.delete(e.id)}t.currentActiveAgent=null,t.userInstructions.push(n),t.userInstructions.length>5&&(t.userInstructions=t.userInstructions.slice(-5))}processTodoWrite(e,t){let s=e.todos||e.data?.todos||e.data||[];if(s&&"object"==typeof s&&s.todos&&(s=s.todos),!Array.isArray(s)||0===s.length)return;t.currentTodos=s.map(t=>({content:t.content,activeForm:t.activeForm,status:t.status,timestamp:e.timestamp}));let n=t.currentActiveAgent;if(!n){const e=this.getAllAgents(t).filter(e=>"active"===e.status||"in_progress"===e.status).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));if(e.length>0)n=e[0];else{const e=this.getAllAgents(t),s=e.find(e=>e.isPM);s?n=s:e.length>0&&(n=e[0])}}if(n){n.todoWritesMap||(n.todoWritesMap=new Map),n.todoWrites||(n.todoWrites=[]);const t=n.todoWritesMap.get("TodoWrite");if(t)t.todos=s,t.timestamp=e.timestamp,t.updateCount=(t.updateCount||1)+1;else{const t={id:`todowrite-${n.id}-${Date.now()}`,name:"TodoWrite",type:"todowrite",icon:"📝",timestamp:e.timestamp,status:"completed",todos:s,params:{todos:s},updateCount:1};n.todoWritesMap.set("TodoWrite",t),n.todoWrites=[t]}n.currentTodos=s}else{t.todoWrites||(t.todoWrites=[]),t.todoWritesMap||(t.todoWritesMap=new Map);const n=t.todoWritesMap.get("TodoWrite");if(n)n.todos=s,n.timestamp=e.timestamp,n.updateCount=(n.updateCount||1)+1;else{const n={id:`todowrite-session-${Date.now()}`,name:"TodoWrite",type:"todowrite",icon:"📝",timestamp:e.timestamp,status:"completed",todos:s,updateCount:1};t.todoWritesMap.set("TodoWrite",n),t.todoWrites=[n]}}}processSubagentStart(e,t){const s=e.agent_name||e.data?.agent_name||e.data?.agent_type||e.agent_type||e.agent||"unknown",n=e.session_id||e.data?.session_id,o=e.parent_agent||e.data?.parent_agent,i=`${s}-${n||"no-session"}`;let a=null;let r;if(a=this.getAllAgents(t).find(e=>e.name===s&&e.sessionId===n&&"active"===e.status),a)r=a,r.timestamp=e.timestamp,r.instanceCount=(r.instanceCount||1)+1,this.expandedAgents.add(r.id);else{if(r={id:`agent-${i}-${Date.now()}`,name:s,type:"agent",icon:this.getAgentIcon(s),timestamp:e.timestamp,status:"active",tools:[],subagents:new Map,sessionId:n,parentAgent:o,isPM:"pm"===s.toLowerCase()||s.toLowerCase().includes("project manager"),instanceCount:1,toolsMap:new Map},o){let e=null;for(let[s,n]of t.agents.entries())if(n.sessionId===o||n.name===o){e=n;break}e?(e.subagents||(e.subagents=new Map),e.subagents.set(r.id,r)):t.agents.set(r.id,r)}else t.agents.set(r.id,r);this.expandedAgents.add(r.id)}t.currentActiveAgent=r}processSubagentStop(e,t){const s=e.session_id||e.data?.session_id;if(s&&t.agents.has(s)){t.agents.get(s).status="completed"}}processToolUse(e,t){const s=e.tool_name||e.data?.tool_name||e.tool||e.data?.tool||"unknown",n=e.tool_parameters||e.data?.tool_parameters||e.parameters||e.data?.parameters||{},o=e.session_id||e.data?.session_id;let i=t.currentActiveAgent;if(!i){const e=this.getAllAgents(t);i=e.find(e=>e.sessionId===o)||e.find(e=>"active"===e.status)||e[0]}if(i){i.toolsMap||(i.toolsMap=new Map),i.tools||(i.tools=[]);const t=this.getToolKey(s,n);let o=i.toolsMap.get(t);if(o)o.params=n,o.timestamp=e.timestamp,o.status="in_progress",o.eventId=e.id,o.callCount=(o.callCount||1)+1,i.currentTool=o;else{const o={id:`tool-${i.id}-${s}-${Date.now()}`,name:s,type:"tool",icon:this.getToolIcon(s),timestamp:e.timestamp,status:"in_progress",params:n,eventId:e.id,callCount:1,createdAt:e.timestamp};"Task"===s&&n.subagent_type&&(o.isSubagentTask=!0,o.subagentType=n.subagent_type),i.toolsMap.set(t,o),"TodoWrite"===s?i.tools.unshift(o):i.tools.push(o),i.currentTool=o}}else{t.tools||(t.tools=[]),t.toolsMap||(t.toolsMap=new Map);const o=this.getToolKey(s,n);let i=t.toolsMap.get(o);if(i)i.params=n,i.timestamp=e.timestamp,i.status="in_progress",i.eventId=e.id,i.callCount=(i.callCount||1)+1,t.currentTool=i;else{const i={id:`tool-session-${s}-${Date.now()}`,name:s,type:"tool",icon:this.getToolIcon(s),timestamp:e.timestamp,status:"in_progress",params:n,eventId:e.id,callCount:1,createdAt:e.timestamp};t.toolsMap.set(o,i),"TodoWrite"===s?t.tools.unshift(i):t.tools.push(i),t.currentTool=i}}}getToolKey(e,t){if("TodoWrite"===e)return"TodoWrite";let s=e;return"Edit"!==e&&"Write"!==e&&"Read"!==e||t.file_path&&(s+=`-${t.file_path}`),"Grep"!==e&&"Glob"!==e||!t.pattern||(s+=`-${t.pattern.substring(0,20)}`),s}updateToolStatus(e,t,s){const n=e.tool_name||e.data?.tool_name||e.tool||"unknown",o=e.tool_parameters||e.data?.tool_parameters||e.parameters||e.data?.parameters||{},i=e.session_id||e.data?.session_id,a=this.getToolKey(n,o);let r=t.currentActiveAgent;if(!r){const e=this.getAllAgents(t);r=e.find(e=>e.sessionId===i)||e.find(e=>"active"===e.status)}if(r&&r.toolsMap){const t=r.toolsMap.get(a);if(t)return t.status=s,t.completedAt=e.timestamp,(e.data?.result||e.result)&&(t.result=e.data?.result||e.result),void(e.data?.duration_ms&&(t.duration=e.data.duration_ms))}if(t.toolsMap){const n=t.toolsMap.get(a);if(n)return n.status=s,n.completedAt=e.timestamp,(e.data?.result||e.result)&&(n.result=e.data?.result||e.result),void(e.data?.duration_ms&&(n.duration=e.data.duration_ms))}console.log(`ActivityTree: Could not find tool to update status for ${n} with key ${a} (event ${e.id})`)}renderTree(){const e=document.getElementById("linear-tree");if(!e)return;e.innerHTML="";const t=Array.from(this.sessions.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));for(let s of t){if("all"!==this.selectedSessionFilter&&this.selectedSessionFilter!==s.id)continue;const t=this.createSessionElement(s);e.appendChild(t)}}createSessionElement(e){const t=this.expandedSessions.has(e.id)||e.expanded;let s;try{const t=e.timestamp instanceof Date?e.timestamp:new Date(e.timestamp);isNaN(t.getTime())?(s="Invalid Date",console.warn("ActivityTree: Invalid session timestamp:",e.timestamp)):s=t.toLocaleString()}catch(l){s="Invalid Date",console.error("ActivityTree: Error formatting session timestamp:",l,e.timestamp)}const n=document.createElement("div");n.className="tree-node session",n.dataset.sessionId=e.id;const o=t?"▼":"▶",i=this.getAllAgents(e).length,a=e.currentTodos?e.currentTodos.length:0,r=e.userInstructions?e.userInstructions.length:0;return console.log(`ActivityTree: Rendering session ${e.id}: ${i} agents, ${r} instructions, ${a} todos at ${s}`),n.innerHTML=`\n <div class="tree-node-content" onclick="window.activityTreeInstance.toggleSession('${e.id}')">\n <span class="tree-expand-icon">${o}</span>\n <span class="tree-icon">🎯</span>\n <span class="tree-label">PM Session</span>\n <span class="tree-meta">${s} • ${i} agent(s) • ${r} instruction(s) • ${a} todo(s)</span>\n </div>\n <div class="tree-children" style="display: ${t?"block":"none"}">\n ${this.renderSessionContent(e)}\n </div>\n `,n}renderSessionContent(e){let t="";if(e.userInstructions&&e.userInstructions.length>0)for(let n of e.userInstructions.slice(-3))t+=this.renderUserInstructionElement(n,1);if(e.tools&&e.tools.length>0)for(let n of e.tools)t+=this.renderToolElement(n,1);const s=Array.from(e.agents.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));for(let n of s)t+=this.renderAgentElement(n,1);return t}renderUserInstructionElement(e,t){return`\n <div class="tree-node user-instruction ${this.selectedItem&&"instruction"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":""}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">💬</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'instruction', event)">User: "${this.escapeHtml(e.preview)}"</span>\n <span class="tree-status status-active">instruction</span>\n </div>\n </div>\n `}renderTodoChecklistElement(e,t){const s=`checklist-${Date.now()}`,n=!1!==this.expandedTools.has(s),o=n?"▼":"▶";let i=0,a=0;e.forEach(e=>{"completed"===e.status?i++:"in_progress"===e.status&&a++});let r="";r=a>0?`${a} in progress, ${i} completed`:i===e.length&&e.length>0?`All ${e.length} completed`:`${e.length} todo(s)`;let l=`\n <div class="tree-node todo-checklist" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoChecklist('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">☑️</span>\n <span class="tree-label">TODOs</span>\n <span class="tree-params">${r}</span>\n <span class="tree-status status-active">checklist</span>\n </div>\n `;if(n){l+='<div class="tree-children">';for(let s of e){const e=this.getCheckboxIcon(s.status),n=`status-${s.status}`,o="in_progress"===s.status?s.activeForm:s.content;l+=`\n <div class="tree-node todo-item ${n}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${e}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${s.status.replace("_"," ")}</span>\n </div>\n </div>\n `}l+="</div>"}return l+="</div>",l}renderAgentElement(e,t){const s="active"===e.status?"status-active":"status-completed",n=this.expandedAgents.has(e.id),o=e.tools&&e.tools.length>0,i=e.subagents&&e.subagents.size>0,a=o||i,r=a?n?"▼":"▶":"",l=this.selectedItem&&"agent"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":"",c=e.instanceCount>1?` (${e.instanceCount}x)`:"";let d="";if(!n&&a){const t=[];if(e.currentTodos&&e.currentTodos.length>0){const s=e.currentTodos.find(e=>"in_progress"===e.status);s&&t.push(`📝 ${s.activeForm||s.content}`)}e.currentTool&&t.push(`${e.currentTool.icon} ${e.currentTool.name}`),t.length>0&&(d=` • ${t.join(" • ")}`)}let p=`\n <div class="tree-node agent ${s} ${l}" data-level="${t}">\n <div class="tree-node-content">\n ${r?`<span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleAgent('${e.id}'); event.stopPropagation();">${r}</span>`:'<span class="tree-expand-icon"></span>'}\n <span class="tree-icon">${e.icon}</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'agent', event)">${e.name}${c}${d}</span>\n <span class="tree-status ${s}">${e.status}</span>\n </div>\n `;if(a&&n){if(p+='<div class="tree-children">',o)for(let s of e.tools)p+=this.renderToolElement(s,t+1);if(i){const s=Array.from(e.subagents.values());for(let e of s)p+=this.renderAgentElement(e,t+1)}p+="</div>"}return p+="</div>",p}renderToolElement(e,t){const s=`status-${e.status}`,n=this.getToolParams(e),o=this.selectedItem&&"tool"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":"",i=this.getToolStatusIcon(e.status),a=this.getToolStatusLabel(e.status),r=e.callCount>1?` (${e.callCount} calls)`:"";return`\n <div class="tree-node tool ${s} ${o}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${e.icon}</span>\n <span class="tree-status-icon">${i}</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'tool', event)">${e.name}${r}</span>\n <span class="tree-params">${n}</span>\n <span class="tree-status ${s}">${a}</span>\n </div>\n </div>\n `}getToolParams(e){if(!e.params)return"";if("Read"===e.name&&e.params.file_path)return e.params.file_path;if("Edit"===e.name&&e.params.file_path)return e.params.file_path;if("Write"===e.name&&e.params.file_path)return e.params.file_path;if("Bash"===e.name&&e.params.command){const t=e.params.command;return t.length>50?t.substring(0,50)+"...":t}return"WebFetch"===e.name&&e.params.url?e.params.url:""}getStatusIcon(e){return{pending:"⏸️",in_progress:"🔄",completed:"✅"}[e]||"❓"}getCheckboxIcon(e){return{pending:"⏳",in_progress:"🔄",completed:"✅"}[e]||"❓"}getAgentIcon(e){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️","project manager":"📊"}[e.toLowerCase()]||"🤖"}getAllAgents(e){const t=[],s=e=>{if(e)for(let n of e.values())t.push(n),n.subagents&&n.subagents.size>0&&s(n.subagents)};return s(e.agents),t}renderTodoWriteElement(e,t){const s=e.id,n=this.expandedTools.has(s),o=n?"▼":"▶",i=e.todos||[];let a=0,r=0;i.forEach(e=>{"completed"===e.status?a++:"in_progress"===e.status&&r++});const l=i.find(e=>"in_progress"===e.status),c=l?` • 🔄 ${l.activeForm||l.content}`:"";let d="";d=r>0?`${r} in progress, ${a}/${i.length} done`:a===i.length&&i.length>0?`All ${i.length} completed ✅`:`${a}/${i.length} done`;let p=`\n <div class="tree-node todowrite ${l?"has-active":""}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoWrite('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">📝</span>\n <span class="tree-label">TodoWrite${e.updateCount>1?` (${e.updateCount} updates)`:""}${n?"":c}</span>\n <span class="tree-params">${d}</span>\n <span class="tree-status status-active">todos</span>\n </div>\n `;if(n&&i.length>0){p+='<div class="tree-children">';for(let e of i){const s=this.getCheckboxIcon(e.status),n=`status-${e.status}`,o="in_progress"===e.status?e.activeForm:e.content;p+=`\n <div class="tree-node todo-item ${n} ${e===l?"current-active":""}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${s}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${e.status.replace("_"," ")}</span>\n </div>\n </div>\n `}p+="</div>"}return p+="</div>",p}toggleTodoWrite(e){this.expandedTools.has(e)?this.expandedTools.delete(e):this.expandedTools.add(e),this.renderTree()}getToolIcon(e){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[e.toLowerCase()]||"🔧"}getToolStatusIcon(e){return{in_progress:"⏳",completed:"✅",failed:"❌",error:"❌",pending:"⏸️",active:"🔄"}[e]||"❓"}getToolStatusLabel(e){return{in_progress:"in progress",completed:"completed",failed:"failed",error:"error",pending:"pending",active:"active"}[e]||e}toggleSession(e){this.expandedSessions.has(e)?this.expandedSessions.delete(e):this.expandedSessions.add(e);const t=this.sessions.get(e);t&&(t.expanded=this.expandedSessions.has(e)),this.renderTree()}expandAllSessions(){for(let e of this.sessions.keys()){this.expandedSessions.add(e);const t=this.sessions.get(e);t&&(t.expanded=!0)}this.renderTree()}collapseAllSessions(){this.expandedSessions.clear();for(let e of this.sessions.values())e.expanded=!1;this.renderTree()}updateStats(){const e=this.countTotalNodes(),t=this.countActiveNodes(),s=this.calculateMaxDepth(),n=document.getElementById("node-count"),o=document.getElementById("active-count"),i=document.getElementById("tree-depth");n&&(n.textContent=e),o&&(o.textContent=t),i&&(i.textContent=s),console.log(`ActivityTree: Stats updated - Nodes: ${e}, Active: ${t}, Depth: ${s}`)}countTotalNodes(){let e=0;for(let t of this.sessions.values()){e+=1,e+=t.agents.size,t.userInstructions&&(e+=t.userInstructions.length),t.todos&&(e+=t.todos.length),t.tools&&(e+=t.tools.length);for(let s of t.agents.values())s.tools&&(e+=s.tools.length)}return e}countActiveNodes(){let e=0;for(let t of this.sessions.values()){if("active"===t.status&&e++,t.todos)for(let s of t.todos)"in_progress"===s.status&&e++;if(t.tools)for(let s of t.tools)"in_progress"===s.status&&e++;for(let s of t.agents.values())if("active"===s.status&&e++,s.tools)for(let t of s.tools)"in_progress"===t.status&&e++}return e}calculateMaxDepth(){let e=0;for(let t of this.sessions.values()){let s=1;t.userInstructions&&t.userInstructions.length>0&&(s=Math.max(s,2)),t.todos&&t.todos.length>0&&(s=Math.max(s,3)),t.tools&&t.tools.length>0&&(s=Math.max(s,2));for(let e of t.agents.values())e.tools&&e.tools.length>0&&(s=Math.max(s,3));e=Math.max(e,s)}return e}toggleAgent(e){this.expandedAgents.has(e)?this.expandedAgents.delete(e):this.expandedAgents.add(e),this.renderTree()}toggleTool(e){console.log("Tool expansion is disabled. Tools now show data in the left pane when clicked.")}toggleTodoChecklist(e){this.expandedTools.has(e)?this.expandedTools.delete(e):this.expandedTools.add(e),this.renderTree()}renderPinnedTodosElement(e,t){const s=`pinned-todos-${Date.now()}`,n=!1!==this.expandedTools.has(s),o=n?"▼":"▶",i=e.todos||[];let a=0,r=0;i.forEach(e=>{"completed"===e.status?a++:"in_progress"===e.status&&r++});let l="";l=r>0?`${r} in progress, ${a} completed`:a===i.length&&i.length>0?`All ${i.length} completed`:`${i.length} todo(s)`;let c=`\n <div class="tree-node pinned-todos" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoChecklist('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">📌</span>\n <span class="tree-label">Pinned TODOs</span>\n <span class="tree-params">${l}</span>\n <span class="tree-status status-active">pinned</span>\n </div>\n `;if(n){c+='<div class="tree-children">';for(let e of i){const s=this.getCheckboxIcon(e.status),n=`status-${e.status}`,o="in_progress"===e.status?e.activeForm:e.content;c+=`\n <div class="tree-node todo-item ${n}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${s}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${e.status.replace("_"," ")}</span>\n </div>\n </div>\n `}c+="</div>"}return c+="</div>",c}selectItem(e,t,s){s&&s.stopPropagation(),this.selectedItem={data:e,type:t},this.displayItemData(e,t),this.renderTree()}displayItemData(t,s){this.unifiedViewer||(this.unifiedViewer=new e("module-data-content")),this.unifiedViewer.display(t,s);const n=document.querySelector(".module-data-header h5");if(n){const e={agent:"🤖",tool:"🔧",instruction:"💬",session:"🎯",todo:"📝"}[s]||"📊",o=t.name||t.agentName||t.tool_name||"Item";n.textContent=`${e} ${s}: ${o}`}}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}resetZoom(){this.svg&&this.zoom&&this.svg.transition().duration(this.duration).call(this.zoom.transform,d3.zoomIdentity)}escapeJson(e){return JSON.stringify(e).replace(/'/g,"&apos;").replace(/"/g,"&quot;")}}window.ActivityTree=t;const s=()=>{let e=null;const s=()=>{e||(console.log("Creating new Activity Tree instance..."),e=new t,window.activityTreeInstance=e,window.activityTree=()=>e),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..."),s(),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..."),s(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))});const n=document.querySelector(".tab-button.active");n&&"activity"===n.getAttribute("data-tab")&&(console.log("Activity tab is active on load, initializing tree..."),s());const o=document.getElementById("activity-tab");o&&o.classList.contains("active")&&(console.log("Activity panel is active on load, initializing tree..."),e||s())};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",s):s();
2
2
  //# sourceMappingURL=activity-tree.js.map