@nogataka/smart-edit 1.0.2 → 1.0.4

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.
@@ -1 +1 @@
1
- :root{--bg-primary: #f2f2f2;--bg-secondary: #ffffff;--text-primary: #1a1a1a;--text-secondary: #3d3d3d;--text-muted: #777;--border-color: #cfcfcf;--btn-primary: #2b2b2b;--btn-hover: #1e1e1e;--btn-disabled: #9c9c9c;--btn-text: #f5f5f5;--shadow: 0 2px 4px rgba(0, 0, 0, .12);--tool-highlight: #e5e5e5;--tool-highlight-text: #1a1a1a;--log-debug: #888;--log-info: #1a1a1a;--log-warning: #454545;--log-error: #111111;--stats-header: #ebebeb;--sidebar-width: 240px;--sidebar-width-collapsed: 64px;--topbar-height: 56px;--content-padding: 24px;--card-bg: var(--bg-secondary);--card-border-radius: 12px;--card-shadow: 0 2px 8px rgba(0, 0, 0, .08);--card-shadow-hover: 0 4px 16px rgba(0, 0, 0, .12);--card-padding: 20px;--spacing-xs: 4px;--spacing-sm: 8px;--spacing-md: 16px;--spacing-lg: 24px;--spacing-xl: 32px;--font-size-xs: 11px;--font-size-sm: 13px;--font-size-base: 14px;--font-size-lg: 16px;--font-size-xl: 20px;--font-size-2xl: 24px;--status-success: #22c55e;--status-warning: #f59e0b;--status-error: #ef4444;--status-info: #3b82f6;--input-bg: var(--bg-primary);--input-border: var(--border-color);--input-focus-border: #3b82f6;--input-focus-ring: rgba(59, 130, 246, .3);--nav-item-hover: rgba(0, 0, 0, .04);--nav-item-active: rgba(59, 130, 246, .1);--nav-item-active-border: #3b82f6;--transition-fast: .15s ease;--transition-normal: .2s ease;--transition-slow: .3s ease}[data-theme=dark]{--bg-primary: #121212;--bg-secondary: #1e1e1e;--text-primary: #f1f1f1;--text-secondary: #d0d0d0;--text-muted: #9a9a9a;--border-color: #2c2c2c;--btn-primary: #ededed;--btn-hover: #d6d6d6;--btn-disabled: #4a4a4a;--btn-text: #111111;--shadow: 0 2px 4px rgba(0, 0, 0, .4);--tool-highlight: #2a2a2a;--tool-highlight-text: #f1f1f1;--log-debug: #a0a0a0;--log-info: #f1f1f1;--log-warning: #c7c7c7;--log-error: #ffffff;--stats-header: #262626;--card-bg: var(--bg-secondary);--card-shadow: 0 2px 8px rgba(0, 0, 0, .3);--card-shadow-hover: 0 4px 16px rgba(0, 0, 0, .4);--input-bg: #1a1a1a;--nav-item-hover: rgba(255, 255, 255, .04);--nav-item-active: rgba(59, 130, 246, .15)}*{box-sizing:border-box}body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,Helvetica,Arial,"Apple Color Emoji","Segoe UI Emoji";margin:0;padding:0;background-color:var(--bg-primary);color:var(--text-primary);transition:background-color .3s ease,color .3s ease;overflow:hidden;height:100vh}#root{height:100%}.header{text-align:center;margin-bottom:20px;font-size:1.5rem;font-weight:700}.log-container{background-color:var(--bg-primary);border:1px solid var(--border-color);border-radius:8px;height:100%;min-height:400px;overflow-y:auto;overflow-x:auto;padding:var(--spacing-md);white-space:pre-wrap;font-size:12px;line-height:1.5;color:var(--text-primary);font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;transition:background-color .3s ease,border-color .3s ease,color .3s ease}.log-card{height:calc(100vh - var(--topbar-height) - var(--content-padding) * 2 - var(--spacing-md))}.controls{display:flex;align-items:center;gap:var(--spacing-sm);flex-wrap:wrap}.btn{background-color:var(--btn-primary);color:var(--btn-text);border:none;padding:8px 16px;border-radius:4px;cursor:pointer;font-size:14px;transition:background-color .3s ease}.btn:hover{background-color:var(--btn-hover)}.btn:disabled{background-color:var(--btn-disabled);color:var(--text-muted);cursor:not-allowed}.theme-toggle{display:flex;align-items:center;justify-content:center;background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:50%;width:36px;height:36px;padding:0;cursor:pointer;transition:background-color .3s ease,border-color .3s ease}.theme-toggle:hover{background-color:var(--border-color)}.theme-toggle .icon{font-size:18px;line-height:1}.language-toggle{display:flex;align-items:center;gap:4px;background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:18px;padding:6px 10px;cursor:pointer;transition:background-color .3s ease,border-color .3s ease}.language-toggle:hover{background-color:var(--border-color)}.language-toggle .icon{display:flex;align-items:center;color:var(--text-primary)}.language-toggle .language-code{font-size:12px;font-weight:600;color:var(--text-primary)}.log-debug{color:var(--log-debug)}.log-info{color:var(--log-info)}.log-warning{color:var(--log-warning);font-weight:600}.log-error{color:var(--log-error);font-weight:700}.log-default{color:var(--log-info)}.tool-name{background-color:var(--tool-highlight);color:var(--tool-highlight-text);font-weight:700;padding:0 2px;border-radius:2px}.loading{text-align:center;color:var(--text-muted);font-style:italic}.error-message{color:var(--log-error);text-align:center;margin:10px 0}.charts-container{display:flex;flex-wrap:wrap;gap:15px;justify-content:space-between;max-width:1400px;margin:0 auto}.chart-group{flex:1;min-width:280px;max-width:320px;text-align:center}.chart-wide{flex:0 0 100%;min-width:100%;margin-top:10px}.chart-group h3{margin:0 0 10px;color:var(--text-secondary)}.stats-summary{margin:0 auto;border-collapse:collapse;background:var(--bg-secondary);border-radius:5px;overflow:hidden;box-shadow:var(--shadow);transition:background-color .3s ease,box-shadow .3s ease}.stats-summary th,.stats-summary td{padding:10px 20px;text-align:left;border-bottom:1px solid var(--border-color);color:var(--text-primary);transition:border-color .3s ease,color .3s ease}.stats-summary th{background-color:var(--stats-header);font-weight:700;transition:background-color .3s ease}.stats-summary tr:last-child td{border-bottom:none}@media(max-width:768px){.charts-container{flex-direction:column}.chart-group,.chart-wide{min-width:auto;max-width:none}.controls{flex-direction:column;gap:5px}}.main-layout{display:flex;height:100vh;overflow:hidden}.sidebar{width:var(--sidebar-width);height:100%;background-color:var(--bg-secondary);border-right:1px solid var(--border-color);display:flex;flex-direction:column;transition:width var(--transition-normal);flex-shrink:0;overflow:hidden}.sidebar.collapsed{width:var(--sidebar-width-collapsed)}.sidebar-header{height:var(--topbar-height);display:flex;align-items:center;justify-content:space-between;padding:0 var(--spacing-md);border-bottom:1px solid var(--border-color);flex-shrink:0}.sidebar-logo{display:flex;align-items:center;gap:var(--spacing-sm);font-weight:600;font-size:var(--font-size-lg);color:var(--text-primary);white-space:nowrap;overflow:hidden}.sidebar-logo-icon{width:28px;height:28px;flex-shrink:0}.sidebar.collapsed .sidebar-logo-text{display:none}.sidebar-toggle{background:none;border:none;cursor:pointer;padding:var(--spacing-xs);border-radius:4px;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;transition:background-color var(--transition-fast)}.sidebar-toggle:hover{background-color:var(--nav-item-hover)}.sidebar-nav{flex:1;padding:var(--spacing-md) var(--spacing-sm);overflow-y:auto}.nav-item{display:flex;align-items:center;gap:var(--spacing-md);padding:var(--spacing-sm) var(--spacing-md);border-radius:8px;cursor:pointer;color:var(--text-secondary);transition:all var(--transition-fast);margin-bottom:var(--spacing-xs);border:none;background:none;width:100%;text-align:left;font-size:var(--font-size-base)}.nav-item:hover{background-color:var(--nav-item-hover);color:var(--text-primary)}.nav-item.active{background-color:var(--nav-item-active);color:var(--nav-item-active-border);font-weight:500}.nav-item-icon{width:20px;height:20px;flex-shrink:0;display:flex;align-items:center;justify-content:center}.nav-item-label{white-space:nowrap;overflow:hidden}.sidebar.collapsed .nav-item-label{display:none}.sidebar.collapsed .nav-item{justify-content:center;padding:var(--spacing-sm)}.sidebar-footer{padding:var(--spacing-md) var(--spacing-sm);border-top:1px solid var(--border-color)}.shutdown-btn{color:var(--status-error)!important}.shutdown-btn:hover{background-color:#ef44441a!important;color:var(--status-error)!important}.main-content{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}.topbar{height:var(--topbar-height);background-color:var(--bg-secondary);border-bottom:1px solid var(--border-color);display:flex;align-items:center;justify-content:space-between;padding:0 var(--content-padding);flex-shrink:0}.topbar-left{display:flex;align-items:center;gap:var(--spacing-md)}.topbar-title{font-size:var(--font-size-lg);font-weight:600;color:var(--text-primary)}.topbar-subtitle{font-size:var(--font-size-sm);color:var(--text-muted)}.topbar-right{display:flex;align-items:center;gap:var(--spacing-md)}.connection-indicator{display:flex;align-items:center;gap:var(--spacing-xs);font-size:var(--font-size-sm);color:var(--text-muted)}.connection-dot{width:8px;height:8px;border-radius:50%;background-color:var(--status-error)}.connection-dot.streaming{background-color:var(--status-success);animation:pulse 2s infinite}.connection-dot.polling{background-color:var(--status-warning)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.content-area{flex:1;overflow-y:auto;padding:var(--content-padding);background-color:var(--bg-primary)}.card{background-color:var(--card-bg);border-radius:var(--card-border-radius);box-shadow:var(--card-shadow);padding:var(--card-padding);transition:box-shadow var(--transition-fast)}.card:hover{box-shadow:var(--card-shadow-hover)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-md)}.card-title{font-size:var(--font-size-lg);font-weight:600;color:var(--text-primary);margin:0}.card-subtitle{font-size:var(--font-size-sm);color:var(--text-muted);margin:var(--spacing-xs) 0 0 0}.card-actions{display:flex;gap:var(--spacing-sm)}.card-body{color:var(--text-primary)}@media(max-width:768px){.sidebar{position:fixed;left:0;top:0;z-index:100;transform:translate(-100%);transition:transform var(--transition-normal)}.sidebar.open{transform:translate(0)}.sidebar-backdrop{position:fixed;inset:0;background-color:#00000080;z-index:99;opacity:0;visibility:hidden;transition:opacity var(--transition-normal)}.sidebar-backdrop.visible{opacity:1;visibility:visible}.topbar{padding:0 var(--spacing-md)}.content-area{padding:var(--spacing-md)}.mobile-menu-btn{display:flex;background:none;border:none;cursor:pointer;padding:var(--spacing-xs);color:var(--text-primary)}}@media(min-width:769px){.mobile-menu-btn,.sidebar-backdrop{display:none}}.log-panel{display:flex;flex-direction:column;gap:var(--spacing-md);height:100%}.log-panel-header{display:flex;flex-direction:column;gap:var(--spacing-md);margin-bottom:var(--spacing-md)}.log-panel-controls{display:flex;align-items:center;gap:var(--spacing-sm)}.log-panel-content{flex:1;min-height:0}@media(max-width:768px){.log-panel-header{gap:var(--spacing-sm)}}.stats-panel{display:flex;flex-direction:column;gap:var(--spacing-lg)}.stats-panel-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--spacing-md)}.stats-panel-actions{display:flex;gap:var(--spacing-sm)}.stats-estimator{font-size:var(--font-size-sm);color:var(--text-muted)}.stats-empty{text-align:center;padding:var(--spacing-xl);color:var(--text-muted)}.stats-empty p{margin:0}.stats-empty-hint{font-size:var(--font-size-sm);margin-top:var(--spacing-sm)!important}.metrics-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--spacing-md)}.metric-card{background-color:var(--card-bg);border-radius:var(--card-border-radius);box-shadow:var(--card-shadow);padding:var(--card-padding);transition:box-shadow var(--transition-fast)}.metric-card:hover{box-shadow:var(--card-shadow-hover)}.metric-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-sm)}.metric-card-title{font-size:var(--font-size-sm);color:var(--text-muted);font-weight:500}.metric-card-icon{color:var(--text-muted)}.metric-card-value{font-size:var(--font-size-2xl);font-weight:700;color:var(--text-primary);line-height:1.2}.metric-card-footer{display:flex;align-items:center;justify-content:space-between;margin-top:var(--spacing-sm)}.metric-card-subtitle{font-size:var(--font-size-xs);color:var(--text-muted)}.metric-card-trend{font-size:var(--font-size-xs);font-weight:600;padding:2px 6px;border-radius:4px}.metric-card-trend.up{color:var(--status-success);background-color:#22c55e1a}.metric-card-trend.down{color:var(--status-error);background-color:#ef44441a}.metric-card-trend.neutral{color:var(--text-muted);background-color:var(--nav-item-hover)}.live-counter{font-variant-numeric:tabular-nums}.stats-charts-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(400px,1fr));gap:var(--spacing-lg)}.stats-charts-row{width:100%}.pie-charts-row{display:flex;gap:var(--spacing-lg);justify-content:center;flex-wrap:wrap}.pie-chart-item{flex:1;min-width:250px;max-width:350px}.chart-container{position:relative;width:100%}.chart-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:200px;color:var(--text-muted);font-style:italic;text-align:center;gap:var(--spacing-xs)}.chart-empty-hint{font-size:.85em;opacity:.7}.activity-chart-wrapper{display:flex;flex-direction:column;gap:var(--spacing-sm)}.chart-actions{display:flex;justify-content:flex-end;padding-top:var(--spacing-sm)}.btn-sm{padding:4px 8px;font-size:.85em}@media(max-width:768px){.metrics-grid{grid-template-columns:repeat(2,1fr)}.stats-charts-grid{grid-template-columns:1fr}.pie-charts-row{flex-direction:column;align-items:center}.pie-chart-item{max-width:none;width:100%}}.session-panel{display:flex;flex-direction:column;gap:var(--spacing-lg)}.session-panel-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:var(--spacing-lg);flex-wrap:wrap;gap:var(--spacing-md)}.session-panel-title{font-size:var(--font-size-lg);font-weight:600;color:var(--text-primary);margin:0}.session-panel-subtitle{font-size:var(--font-size-sm);color:var(--text-muted);margin:var(--spacing-xs) 0 0 0}.session-panel-actions{display:flex;gap:var(--spacing-sm)}.session-list{display:flex;flex-direction:column;gap:var(--spacing-md)}.session-list-empty{text-align:center;padding:var(--spacing-xl);color:var(--text-muted)}.session-list-empty p{margin:0}.session-list-empty-hint{font-size:var(--font-size-sm);margin-top:var(--spacing-sm)!important}.session-item{background-color:var(--bg-primary);border:1px solid var(--border-color);border-radius:8px;padding:var(--spacing-md);transition:border-color var(--transition-fast)}.session-item:hover{border-color:var(--text-muted)}.session-item-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:var(--spacing-sm)}.session-item-info{display:flex;flex-direction:column;gap:2px}.session-item-date{font-size:var(--font-size-base);font-weight:600;color:var(--text-primary)}.session-item-time{font-size:var(--font-size-sm);color:var(--text-muted)}.session-item-duration{font-size:var(--font-size-sm);color:var(--text-secondary);background-color:var(--nav-item-hover);padding:2px 8px;border-radius:4px}.session-item-project{font-size:var(--font-size-sm);color:var(--text-secondary);margin-bottom:var(--spacing-sm)}.session-item-stats{display:flex;gap:var(--spacing-lg);margin-bottom:var(--spacing-sm)}.session-stat{display:flex;flex-direction:column;gap:2px}.session-stat-label{font-size:var(--font-size-xs);color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}.session-stat-value{font-size:var(--font-size-base);font-weight:600;color:var(--text-primary);font-variant-numeric:tabular-nums}.session-item-actions{display:flex;gap:var(--spacing-sm);justify-content:flex-end}.session-action-btn{display:flex;align-items:center;gap:4px;padding:6px 12px;font-size:var(--font-size-sm);color:var(--text-secondary);background:none;border:1px solid var(--border-color);border-radius:4px;cursor:pointer;transition:all var(--transition-fast)}.session-action-btn:hover{color:var(--text-primary);border-color:var(--text-muted);background-color:var(--nav-item-hover)}.btn-danger{background-color:transparent;color:var(--status-error);border:1px solid var(--status-error)}.btn-danger:hover{background-color:var(--status-error);color:#fff}.export-btn{display:flex;align-items:center}@media(max-width:768px){.session-panel-header{flex-direction:column;align-items:stretch}.session-panel-actions{justify-content:flex-end}.session-item-stats{flex-wrap:wrap;gap:var(--spacing-md)}}.dashboard-overview{display:flex;flex-direction:column;gap:var(--spacing-lg)}.welcome-section{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-md)}.welcome-content{flex:1}.welcome-title{font-size:var(--font-size-xl);font-weight:600;color:var(--text-primary);margin:0 0 var(--spacing-xs) 0}.welcome-description{font-size:var(--font-size-base);color:var(--text-secondary);margin:0}.connection-badge{flex-shrink:0}.connection-status{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:20px;font-size:var(--font-size-sm);font-weight:500}.connection-status:before{content:"";width:8px;height:8px;border-radius:50%}.connection-status.streaming{background-color:#22c55e1a;color:var(--status-success)}.connection-status.streaming:before{background-color:var(--status-success);animation:pulse 2s infinite}.connection-status.polling{background-color:#f59e0b1a;color:var(--status-warning)}.connection-status.polling:before{background-color:var(--status-warning)}.connection-status.disconnected{background-color:#ef44441a;color:var(--status-error)}.connection-status.disconnected:before{background-color:var(--status-error)}.quick-nav-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:var(--spacing-md)}.quick-nav-card{display:flex;align-items:center;gap:var(--spacing-md);padding:var(--spacing-md);background-color:var(--bg-primary);border:1px solid var(--border-color);border-radius:8px;cursor:pointer;transition:all var(--transition-fast);text-align:left;width:100%}.quick-nav-card:hover{border-color:var(--input-focus-border);background-color:var(--nav-item-active)}.quick-nav-icon{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:8px;background-color:var(--nav-item-active);color:var(--input-focus-border);flex-shrink:0}.quick-nav-content{flex:1;min-width:0}.quick-nav-title{font-size:var(--font-size-base);font-weight:600;color:var(--text-primary);margin:0}.quick-nav-description{font-size:var(--font-size-sm);color:var(--text-muted);margin:4px 0 0}.quick-nav-arrow{color:var(--text-muted);flex-shrink:0;transition:transform var(--transition-fast)}.quick-nav-card:hover .quick-nav-arrow{transform:translate(4px);color:var(--input-focus-border)}@media(max-width:768px){.welcome-section{flex-direction:column}.quick-nav-grid{grid-template-columns:1fr}}.search-input-wrapper{position:relative;display:flex;align-items:center}.search-input-icon{position:absolute;left:12px;color:var(--text-muted);pointer-events:none;display:flex;align-items:center}.search-input{width:100%;padding:8px 36px;border:1px solid var(--input-border);border-radius:6px;background-color:var(--input-bg);color:var(--text-primary);font-size:var(--font-size-sm);transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.search-input:focus{outline:none;border-color:var(--input-focus-border);box-shadow:0 0 0 3px var(--input-focus-ring)}.search-input::placeholder{color:var(--text-muted)}.search-input-clear{position:absolute;right:8px;display:flex;align-items:center;justify-content:center;padding:4px;border:none;background:none;color:var(--text-muted);cursor:pointer;border-radius:4px;transition:color var(--transition-fast),background-color var(--transition-fast)}.search-input-clear:hover{color:var(--text-primary);background-color:var(--nav-item-hover)}.dropdown{position:relative;display:inline-block;min-width:140px}.dropdown-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;padding:8px 12px;border:1px solid var(--input-border);border-radius:6px;background-color:var(--input-bg);color:var(--text-primary);font-size:var(--font-size-sm);cursor:pointer;transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.dropdown-trigger:hover{border-color:var(--text-muted)}.dropdown-trigger:focus{outline:none;border-color:var(--input-focus-border);box-shadow:0 0 0 3px var(--input-focus-ring)}.dropdown-text{flex:1;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dropdown-arrow{display:flex;align-items:center;margin-left:8px;color:var(--text-muted);transition:transform var(--transition-fast)}.dropdown-arrow.open{transform:rotate(180deg)}.dropdown-menu{position:absolute;top:100%;left:0;right:0;margin-top:4px;padding:4px;border:1px solid var(--border-color);border-radius:6px;background-color:var(--bg-secondary);box-shadow:var(--card-shadow);z-index:100;max-height:240px;overflow-y:auto}.dropdown-clear{display:block;width:100%;padding:6px 8px;border:none;background:none;color:var(--status-info);font-size:var(--font-size-xs);text-align:left;cursor:pointer;border-bottom:1px solid var(--border-color);margin-bottom:4px}.dropdown-clear:hover{text-decoration:underline}.dropdown-options{display:flex;flex-direction:column;gap:2px}.dropdown-option{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;cursor:pointer;transition:background-color var(--transition-fast)}.dropdown-option:hover{background-color:var(--nav-item-hover)}.dropdown-option input[type=checkbox],.dropdown-option input[type=radio]{margin:0;accent-color:var(--input-focus-border)}.dropdown-option-label{font-size:var(--font-size-sm);color:var(--text-primary)}.log-filter-bar{display:flex;align-items:center;gap:var(--spacing-md);flex-wrap:wrap}.log-filter-search{flex:1;min-width:200px;max-width:300px}.log-filter-dropdowns{display:flex;align-items:center;gap:var(--spacing-sm)}.log-filter-clear{padding:8px 12px;font-size:var(--font-size-sm)}.icon-btn{display:flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid var(--input-border);border-radius:6px;background-color:var(--input-bg);color:var(--text-secondary);cursor:pointer;transition:all var(--transition-fast)}.icon-btn:hover{border-color:var(--text-muted);color:var(--text-primary);background-color:var(--nav-item-hover)}.icon-btn:disabled{opacity:.5;cursor:not-allowed}.reload-btn.spinning svg{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.filter-stats{display:flex;align-items:center;gap:var(--spacing-sm);font-size:var(--font-size-sm);color:var(--text-muted)}.filter-stats-count{font-weight:600;color:var(--text-primary)}@media(max-width:768px){.log-filter-bar{flex-direction:column;align-items:stretch}.log-filter-search{max-width:none}.log-filter-dropdowns{flex-wrap:wrap}.dropdown{flex:1;min-width:120px}}
1
+ :root{--bg-primary: #f2f2f2;--bg-secondary: #ffffff;--text-primary: #1a1a1a;--text-secondary: #3d3d3d;--text-muted: #777;--border-color: #cfcfcf;--btn-primary: #2b2b2b;--btn-hover: #1e1e1e;--btn-disabled: #9c9c9c;--btn-text: #f5f5f5;--shadow: 0 2px 4px rgba(0, 0, 0, .12);--tool-highlight: #e5e5e5;--tool-highlight-text: #1a1a1a;--log-debug: #888;--log-info: #1a1a1a;--log-warning: #454545;--log-error: #111111;--stats-header: #ebebeb;--sidebar-width: 240px;--sidebar-width-collapsed: 64px;--topbar-height: 56px;--content-padding: 24px;--card-bg: var(--bg-secondary);--card-border-radius: 12px;--card-shadow: 0 2px 8px rgba(0, 0, 0, .08);--card-shadow-hover: 0 4px 16px rgba(0, 0, 0, .12);--card-padding: 20px;--spacing-xs: 4px;--spacing-sm: 8px;--spacing-md: 16px;--spacing-lg: 24px;--spacing-xl: 32px;--font-size-xs: 11px;--font-size-sm: 13px;--font-size-base: 14px;--font-size-lg: 16px;--font-size-xl: 20px;--font-size-2xl: 24px;--status-success: #22c55e;--status-warning: #f59e0b;--status-error: #ef4444;--status-info: #3b82f6;--input-bg: var(--bg-primary);--input-border: var(--border-color);--input-focus-border: #3b82f6;--input-focus-ring: rgba(59, 130, 246, .3);--nav-item-hover: rgba(0, 0, 0, .04);--nav-item-active: rgba(59, 130, 246, .1);--nav-item-active-border: #3b82f6;--transition-fast: .15s ease;--transition-normal: .2s ease;--transition-slow: .3s ease}[data-theme=dark]{--bg-primary: #121212;--bg-secondary: #1e1e1e;--text-primary: #f1f1f1;--text-secondary: #d0d0d0;--text-muted: #9a9a9a;--border-color: #2c2c2c;--btn-primary: #ededed;--btn-hover: #d6d6d6;--btn-disabled: #4a4a4a;--btn-text: #111111;--shadow: 0 2px 4px rgba(0, 0, 0, .4);--tool-highlight: #2a2a2a;--tool-highlight-text: #f1f1f1;--log-debug: #a0a0a0;--log-info: #f1f1f1;--log-warning: #c7c7c7;--log-error: #ffffff;--stats-header: #262626;--card-bg: var(--bg-secondary);--card-shadow: 0 2px 8px rgba(0, 0, 0, .3);--card-shadow-hover: 0 4px 16px rgba(0, 0, 0, .4);--input-bg: #1a1a1a;--nav-item-hover: rgba(255, 255, 255, .04);--nav-item-active: rgba(59, 130, 246, .15)}*{box-sizing:border-box}body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,Helvetica,Arial,"Apple Color Emoji","Segoe UI Emoji";margin:0;padding:0;background-color:var(--bg-primary);color:var(--text-primary);transition:background-color .3s ease,color .3s ease;overflow:hidden;height:100vh}#root{height:100%}.header{text-align:center;margin-bottom:20px;font-size:1.5rem;font-weight:700}.log-container{background-color:var(--bg-primary);border:1px solid var(--border-color);border-radius:8px;height:100%;min-height:400px;overflow-y:auto;overflow-x:auto;padding:var(--spacing-md);white-space:pre-wrap;font-size:12px;line-height:1.5;color:var(--text-primary);font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;transition:background-color .3s ease,border-color .3s ease,color .3s ease}.log-card{height:calc(100vh - var(--topbar-height) - var(--content-padding) * 2 - var(--spacing-md))}.controls{display:flex;align-items:center;gap:var(--spacing-sm);flex-wrap:wrap}.btn{background-color:var(--btn-primary);color:var(--btn-text);border:none;padding:8px 16px;border-radius:4px;cursor:pointer;font-size:14px;transition:background-color .3s ease}.btn:hover{background-color:var(--btn-hover)}.btn:disabled{background-color:var(--btn-disabled);color:var(--text-muted);cursor:not-allowed}.theme-toggle{display:flex;align-items:center;justify-content:center;background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:50%;width:36px;height:36px;padding:0;cursor:pointer;transition:background-color .3s ease,border-color .3s ease}.theme-toggle:hover{background-color:var(--border-color)}.theme-toggle .icon{font-size:18px;line-height:1}.language-toggle{display:flex;align-items:center;gap:4px;background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:18px;padding:6px 10px;cursor:pointer;transition:background-color .3s ease,border-color .3s ease}.language-toggle:hover{background-color:var(--border-color)}.language-toggle .icon{display:flex;align-items:center;color:var(--text-primary)}.language-toggle .language-code{font-size:12px;font-weight:600;color:var(--text-primary)}.log-debug{color:var(--log-debug)}.log-info{color:var(--log-info)}.log-warning{color:var(--log-warning);font-weight:600}.log-error{color:var(--log-error);font-weight:700}.log-default{color:var(--log-info)}.tool-name{background-color:var(--tool-highlight);color:var(--tool-highlight-text);font-weight:700;padding:0 2px;border-radius:2px}.loading{text-align:center;color:var(--text-muted);font-style:italic}.error-message{color:var(--log-error);text-align:center;margin:10px 0}.charts-container{display:flex;flex-wrap:wrap;gap:15px;justify-content:space-between;max-width:1400px;margin:0 auto}.chart-group{flex:1;min-width:280px;max-width:320px;text-align:center}.chart-wide{flex:0 0 100%;min-width:100%;margin-top:10px}.chart-group h3{margin:0 0 10px;color:var(--text-secondary)}.stats-summary{margin:0 auto;border-collapse:collapse;background:var(--bg-secondary);border-radius:5px;overflow:hidden;box-shadow:var(--shadow);transition:background-color .3s ease,box-shadow .3s ease}.stats-summary th,.stats-summary td{padding:10px 20px;text-align:left;border-bottom:1px solid var(--border-color);color:var(--text-primary);transition:border-color .3s ease,color .3s ease}.stats-summary th{background-color:var(--stats-header);font-weight:700;transition:background-color .3s ease}.stats-summary tr:last-child td{border-bottom:none}@media(max-width:768px){.charts-container{flex-direction:column}.chart-group,.chart-wide{min-width:auto;max-width:none}.controls{flex-direction:column;gap:5px}}.main-layout{display:flex;height:100vh;overflow:hidden}.sidebar{width:var(--sidebar-width);height:100%;background-color:var(--bg-secondary);border-right:1px solid var(--border-color);display:flex;flex-direction:column;transition:width var(--transition-normal);flex-shrink:0;overflow:hidden}.sidebar.collapsed{width:var(--sidebar-width-collapsed)}.sidebar-header{height:var(--topbar-height);display:flex;align-items:center;justify-content:space-between;padding:0 var(--spacing-md);border-bottom:1px solid var(--border-color);flex-shrink:0}.sidebar-logo{display:flex;align-items:center;gap:var(--spacing-sm);font-weight:600;font-size:var(--font-size-lg);color:var(--text-primary);white-space:nowrap;overflow:hidden}.sidebar-logo-icon{width:28px;height:28px;flex-shrink:0}.sidebar.collapsed .sidebar-logo-text{display:none}.sidebar-toggle{background:none;border:none;cursor:pointer;padding:var(--spacing-xs);border-radius:4px;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;transition:background-color var(--transition-fast)}.sidebar-toggle:hover{background-color:var(--nav-item-hover)}.sidebar-content{flex:1;padding:var(--spacing-md);overflow-y:auto}.sidebar-section{margin-bottom:var(--spacing-lg)}.sidebar-section-title{font-size:var(--font-size-xs);font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin:0 0 var(--spacing-sm) 0}.project-info{display:flex;flex-direction:column;gap:var(--spacing-sm)}.project-name{display:flex;align-items:center;gap:var(--spacing-sm);color:var(--text-primary);font-weight:600;font-size:var(--font-size-base)}.project-name-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.project-path{font-size:var(--font-size-xs);color:var(--text-muted);word-break:break-all;line-height:1.4}.project-empty{color:var(--text-muted);font-size:var(--font-size-sm);font-style:italic}.instance-list{display:flex;flex-direction:column;gap:var(--spacing-xs)}.instance-item{display:flex;align-items:center;gap:var(--spacing-sm);width:100%;padding:var(--spacing-sm) var(--spacing-md);border-radius:6px;cursor:pointer;border:none;background:none;color:var(--text-secondary);font-size:var(--font-size-sm);text-align:left;transition:all var(--transition-fast)}.instance-item:hover{background-color:var(--nav-item-hover);color:var(--text-primary)}.instance-item.active{background-color:var(--nav-item-active);color:var(--text-primary)}.instance-indicator{width:8px;height:8px;border-radius:50%;background-color:var(--text-muted);flex-shrink:0}.instance-indicator.active{background-color:var(--status-success)}.instance-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sidebar-footer{padding:var(--spacing-md);border-top:1px solid var(--border-color)}.sidebar-action-btn{display:flex;align-items:center;gap:var(--spacing-sm);width:100%;padding:var(--spacing-sm) var(--spacing-md);border-radius:6px;cursor:pointer;border:none;background:none;font-size:var(--font-size-sm);transition:all var(--transition-fast)}.sidebar-action-btn.shutdown-btn{color:var(--status-error)}.sidebar-action-btn.shutdown-btn:hover{background-color:#ef44441a}.main-content{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}.topbar{height:var(--topbar-height);background-color:var(--bg-secondary);border-bottom:1px solid var(--border-color);display:flex;align-items:center;justify-content:space-between;padding:0 var(--content-padding);flex-shrink:0}.topbar-nav{display:flex;align-items:center;gap:var(--spacing-xs)}.topbar-nav-item{display:flex;align-items:center;gap:var(--spacing-xs);padding:var(--spacing-xs) var(--spacing-md);border-radius:6px;cursor:pointer;color:var(--text-secondary);transition:all var(--transition-fast);border:none;background:none;font-size:var(--font-size-sm);font-weight:500}.topbar-nav-item:hover{background-color:var(--nav-item-hover);color:var(--text-primary)}.topbar-nav-item.active{background-color:var(--nav-item-active);color:var(--nav-item-active-border)}.topbar-nav-icon{display:flex;align-items:center;justify-content:center}.topbar-nav-label{white-space:nowrap}.topbar-right{display:flex;align-items:center;gap:var(--spacing-md)}.connection-indicator{display:flex;align-items:center;gap:var(--spacing-xs);font-size:var(--font-size-sm);color:var(--text-muted)}.connection-dot{width:8px;height:8px;border-radius:50%;background-color:var(--status-error)}.connection-dot.streaming{background-color:var(--status-success);animation:pulse 2s infinite}.connection-dot.polling{background-color:var(--status-warning)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.content-area{flex:1;overflow-y:auto;padding:var(--content-padding);background-color:var(--bg-primary)}.card{background-color:var(--card-bg);border-radius:var(--card-border-radius);box-shadow:var(--card-shadow);padding:var(--card-padding);transition:box-shadow var(--transition-fast)}.card:hover{box-shadow:var(--card-shadow-hover)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-md)}.card-title{font-size:var(--font-size-lg);font-weight:600;color:var(--text-primary);margin:0}.card-subtitle{font-size:var(--font-size-sm);color:var(--text-muted);margin:var(--spacing-xs) 0 0 0}.card-actions{display:flex;gap:var(--spacing-sm)}.card-body{color:var(--text-primary)}@media(max-width:768px){.sidebar{position:fixed;left:0;top:0;z-index:100;transform:translate(-100%);transition:transform var(--transition-normal)}.sidebar.open{transform:translate(0)}.sidebar-backdrop{position:fixed;inset:0;background-color:#00000080;z-index:99;opacity:0;visibility:hidden;transition:opacity var(--transition-normal)}.sidebar-backdrop.visible{opacity:1;visibility:visible}.topbar{padding:0 var(--spacing-md)}.content-area{padding:var(--spacing-md)}.mobile-menu-btn{display:flex;background:none;border:none;cursor:pointer;padding:var(--spacing-xs);color:var(--text-primary)}}@media(min-width:769px){.mobile-menu-btn,.sidebar-backdrop{display:none}}.log-panel{display:flex;flex-direction:column;gap:var(--spacing-md);height:100%}.log-panel-header{display:flex;flex-direction:column;gap:var(--spacing-md);margin-bottom:var(--spacing-md)}.log-panel-controls{display:flex;align-items:center;gap:var(--spacing-sm)}.log-panel-content{flex:1;min-height:0}@media(max-width:768px){.log-panel-header{gap:var(--spacing-sm)}}.stats-panel{display:flex;flex-direction:column;gap:var(--spacing-lg)}.stats-panel-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--spacing-md)}.stats-panel-actions{display:flex;gap:var(--spacing-sm)}.stats-estimator{font-size:var(--font-size-sm);color:var(--text-muted)}.stats-empty{text-align:center;padding:var(--spacing-xl);color:var(--text-muted)}.stats-empty p{margin:0}.stats-empty-hint{font-size:var(--font-size-sm);margin-top:var(--spacing-sm)!important}.metrics-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--spacing-md)}.metric-card{background-color:var(--card-bg);border-radius:var(--card-border-radius);box-shadow:var(--card-shadow);padding:var(--card-padding);transition:box-shadow var(--transition-fast)}.metric-card:hover{box-shadow:var(--card-shadow-hover)}.metric-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-sm)}.metric-card-title{font-size:var(--font-size-sm);color:var(--text-muted);font-weight:500}.metric-card-icon{color:var(--text-muted)}.metric-card-value{font-size:var(--font-size-2xl);font-weight:700;color:var(--text-primary);line-height:1.2}.metric-card-footer{display:flex;align-items:center;justify-content:space-between;margin-top:var(--spacing-sm)}.metric-card-subtitle{font-size:var(--font-size-xs);color:var(--text-muted)}.metric-card-trend{font-size:var(--font-size-xs);font-weight:600;padding:2px 6px;border-radius:4px}.metric-card-trend.up{color:var(--status-success);background-color:#22c55e1a}.metric-card-trend.down{color:var(--status-error);background-color:#ef44441a}.metric-card-trend.neutral{color:var(--text-muted);background-color:var(--nav-item-hover)}.live-counter{font-variant-numeric:tabular-nums}.stats-charts-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(400px,1fr));gap:var(--spacing-lg)}.stats-charts-row{width:100%}.pie-charts-row{display:flex;gap:var(--spacing-lg);justify-content:center;flex-wrap:wrap}.pie-chart-item{flex:1;min-width:250px;max-width:350px}.chart-container{position:relative;width:100%}.chart-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;height:200px;color:var(--text-muted);font-style:italic;text-align:center;gap:var(--spacing-xs)}.chart-empty-hint{font-size:.85em;opacity:.7}.activity-chart-wrapper{display:flex;flex-direction:column;gap:var(--spacing-sm)}.chart-actions{display:flex;justify-content:flex-end;padding-top:var(--spacing-sm)}.btn-sm{padding:4px 8px;font-size:.85em}@media(max-width:768px){.metrics-grid{grid-template-columns:repeat(2,1fr)}.stats-charts-grid{grid-template-columns:1fr}.pie-charts-row{flex-direction:column;align-items:center}.pie-chart-item{max-width:none;width:100%}}.session-panel{display:flex;flex-direction:column;gap:var(--spacing-lg)}.session-panel-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:var(--spacing-lg);flex-wrap:wrap;gap:var(--spacing-md)}.session-panel-title{font-size:var(--font-size-lg);font-weight:600;color:var(--text-primary);margin:0}.session-panel-subtitle{font-size:var(--font-size-sm);color:var(--text-muted);margin:var(--spacing-xs) 0 0 0}.session-panel-actions{display:flex;gap:var(--spacing-sm)}.session-list{display:flex;flex-direction:column;gap:var(--spacing-md)}.session-list-empty{text-align:center;padding:var(--spacing-xl);color:var(--text-muted)}.session-list-empty p{margin:0}.session-list-empty-hint{font-size:var(--font-size-sm);margin-top:var(--spacing-sm)!important}.session-item{background-color:var(--bg-primary);border:1px solid var(--border-color);border-radius:8px;padding:var(--spacing-md);transition:border-color var(--transition-fast)}.session-item:hover{border-color:var(--text-muted)}.session-item-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:var(--spacing-sm)}.session-item-info{display:flex;flex-direction:column;gap:2px}.session-item-date{font-size:var(--font-size-base);font-weight:600;color:var(--text-primary)}.session-item-time{font-size:var(--font-size-sm);color:var(--text-muted)}.session-item-duration{font-size:var(--font-size-sm);color:var(--text-secondary);background-color:var(--nav-item-hover);padding:2px 8px;border-radius:4px}.session-item-project{font-size:var(--font-size-sm);color:var(--text-secondary);margin-bottom:var(--spacing-sm)}.session-item-stats{display:flex;gap:var(--spacing-lg);margin-bottom:var(--spacing-sm)}.session-stat{display:flex;flex-direction:column;gap:2px}.session-stat-label{font-size:var(--font-size-xs);color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px}.session-stat-value{font-size:var(--font-size-base);font-weight:600;color:var(--text-primary);font-variant-numeric:tabular-nums}.session-item-actions{display:flex;gap:var(--spacing-sm);justify-content:flex-end}.session-action-btn{display:flex;align-items:center;gap:4px;padding:6px 12px;font-size:var(--font-size-sm);color:var(--text-secondary);background:none;border:1px solid var(--border-color);border-radius:4px;cursor:pointer;transition:all var(--transition-fast)}.session-action-btn:hover{color:var(--text-primary);border-color:var(--text-muted);background-color:var(--nav-item-hover)}.btn-danger{background-color:transparent;color:var(--status-error);border:1px solid var(--status-error)}.btn-danger:hover{background-color:var(--status-error);color:#fff}.export-btn{display:flex;align-items:center}@media(max-width:768px){.session-panel-header{flex-direction:column;align-items:stretch}.session-panel-actions{justify-content:flex-end}.session-item-stats{flex-wrap:wrap;gap:var(--spacing-md)}}.dashboard-overview{display:flex;flex-direction:column;gap:var(--spacing-lg)}.welcome-section{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--spacing-md)}.welcome-content{flex:1}.welcome-title{font-size:var(--font-size-xl);font-weight:600;color:var(--text-primary);margin:0 0 var(--spacing-xs) 0}.welcome-description{font-size:var(--font-size-base);color:var(--text-secondary);margin:0}.connection-badge{flex-shrink:0}.connection-status{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:20px;font-size:var(--font-size-sm);font-weight:500}.connection-status:before{content:"";width:8px;height:8px;border-radius:50%}.connection-status.streaming{background-color:#22c55e1a;color:var(--status-success)}.connection-status.streaming:before{background-color:var(--status-success);animation:pulse 2s infinite}.connection-status.polling{background-color:#f59e0b1a;color:var(--status-warning)}.connection-status.polling:before{background-color:var(--status-warning)}.connection-status.disconnected{background-color:#ef44441a;color:var(--status-error)}.connection-status.disconnected:before{background-color:var(--status-error)}.quick-nav-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:var(--spacing-md)}.quick-nav-card{display:flex;align-items:center;gap:var(--spacing-md);padding:var(--spacing-md);background-color:var(--bg-primary);border:1px solid var(--border-color);border-radius:8px;cursor:pointer;transition:all var(--transition-fast);text-align:left;width:100%}.quick-nav-card:hover{border-color:var(--input-focus-border);background-color:var(--nav-item-active)}.quick-nav-icon{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:8px;background-color:var(--nav-item-active);color:var(--input-focus-border);flex-shrink:0}.quick-nav-content{flex:1;min-width:0}.quick-nav-title{font-size:var(--font-size-base);font-weight:600;color:var(--text-primary);margin:0}.quick-nav-description{font-size:var(--font-size-sm);color:var(--text-muted);margin:4px 0 0}.quick-nav-arrow{color:var(--text-muted);flex-shrink:0;transition:transform var(--transition-fast)}.quick-nav-card:hover .quick-nav-arrow{transform:translate(4px);color:var(--input-focus-border)}@media(max-width:768px){.welcome-section{flex-direction:column}.quick-nav-grid{grid-template-columns:1fr}}.search-input-wrapper{position:relative;display:flex;align-items:center}.search-input-icon{position:absolute;left:12px;color:var(--text-muted);pointer-events:none;display:flex;align-items:center}.search-input{width:100%;padding:8px 36px;border:1px solid var(--input-border);border-radius:6px;background-color:var(--input-bg);color:var(--text-primary);font-size:var(--font-size-sm);transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.search-input:focus{outline:none;border-color:var(--input-focus-border);box-shadow:0 0 0 3px var(--input-focus-ring)}.search-input::placeholder{color:var(--text-muted)}.search-input-clear{position:absolute;right:8px;display:flex;align-items:center;justify-content:center;padding:4px;border:none;background:none;color:var(--text-muted);cursor:pointer;border-radius:4px;transition:color var(--transition-fast),background-color var(--transition-fast)}.search-input-clear:hover{color:var(--text-primary);background-color:var(--nav-item-hover)}.dropdown{position:relative;display:inline-block;min-width:140px}.dropdown-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;padding:8px 12px;border:1px solid var(--input-border);border-radius:6px;background-color:var(--input-bg);color:var(--text-primary);font-size:var(--font-size-sm);cursor:pointer;transition:border-color var(--transition-fast),box-shadow var(--transition-fast)}.dropdown-trigger:hover{border-color:var(--text-muted)}.dropdown-trigger:focus{outline:none;border-color:var(--input-focus-border);box-shadow:0 0 0 3px var(--input-focus-ring)}.dropdown-text{flex:1;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dropdown-arrow{display:flex;align-items:center;margin-left:8px;color:var(--text-muted);transition:transform var(--transition-fast)}.dropdown-arrow.open{transform:rotate(180deg)}.dropdown-menu{position:absolute;top:100%;left:0;right:0;margin-top:4px;padding:4px;border:1px solid var(--border-color);border-radius:6px;background-color:var(--bg-secondary);box-shadow:var(--card-shadow);z-index:100;max-height:240px;overflow-y:auto}.dropdown-clear{display:block;width:100%;padding:6px 8px;border:none;background:none;color:var(--status-info);font-size:var(--font-size-xs);text-align:left;cursor:pointer;border-bottom:1px solid var(--border-color);margin-bottom:4px}.dropdown-clear:hover{text-decoration:underline}.dropdown-options{display:flex;flex-direction:column;gap:2px}.dropdown-option{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;cursor:pointer;transition:background-color var(--transition-fast)}.dropdown-option:hover{background-color:var(--nav-item-hover)}.dropdown-option input[type=checkbox],.dropdown-option input[type=radio]{margin:0;accent-color:var(--input-focus-border)}.dropdown-option-label{font-size:var(--font-size-sm);color:var(--text-primary)}.log-filter-bar{display:flex;align-items:center;gap:var(--spacing-md);flex-wrap:wrap}.log-filter-search{flex:1;min-width:200px;max-width:300px}.log-filter-dropdowns{display:flex;align-items:center;gap:var(--spacing-sm)}.log-filter-clear{padding:8px 12px;font-size:var(--font-size-sm)}.icon-btn{display:flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:1px solid var(--input-border);border-radius:6px;background-color:var(--input-bg);color:var(--text-secondary);cursor:pointer;transition:all var(--transition-fast)}.icon-btn:hover{border-color:var(--text-muted);color:var(--text-primary);background-color:var(--nav-item-hover)}.icon-btn:disabled{opacity:.5;cursor:not-allowed}.reload-btn.spinning svg{animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.filter-stats{display:flex;align-items:center;gap:var(--spacing-sm);font-size:var(--font-size-sm);color:var(--text-muted)}.filter-stats-count{font-weight:600;color:var(--text-primary)}@media(max-width:768px){.log-filter-bar{flex-direction:column;align-items:stretch}.log-filter-search{max-width:none}.log-filter-dropdowns{flex-wrap:wrap}.dropdown{flex:1;min-width:120px}}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Standalone Dashboard Server for Multi-Instance Mode
3
+ *
4
+ * This server runs independently from MCP servers and provides:
5
+ * - Static file serving for the dashboard UI
6
+ * - API endpoints to list registered instances
7
+ * - Proxy capabilities to forward requests to individual MCP instances
8
+ */
9
+ export interface StandaloneDashboardOptions {
10
+ port?: number;
11
+ }
12
+ export declare class StandaloneDashboardServer {
13
+ private server;
14
+ private listeningPort;
15
+ private readonly requestedPort;
16
+ constructor(options?: StandaloneDashboardOptions);
17
+ start(): Promise<number>;
18
+ stop(): void;
19
+ getPort(): number | null;
20
+ private startServer;
21
+ private listenOnPort;
22
+ private handleRequest;
23
+ private handleGetInstances;
24
+ private serveDashboardAsset;
25
+ private respondNotFound;
26
+ private respondMethodNotAllowed;
27
+ private sendJson;
28
+ }
29
+ /**
30
+ * Start a standalone dashboard server and wait for shutdown signal.
31
+ */
32
+ export declare function runStandaloneDashboard(options?: StandaloneDashboardOptions): Promise<void>;
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Standalone Dashboard Server for Multi-Instance Mode
3
+ *
4
+ * This server runs independently from MCP servers and provides:
5
+ * - Static file serving for the dashboard UI
6
+ * - API endpoints to list registered instances
7
+ * - Proxy capabilities to forward requests to individual MCP instances
8
+ */
9
+ import { Buffer } from 'node:buffer';
10
+ import { createServer } from 'node:http';
11
+ import { parse as parseUrl } from 'node:url';
12
+ import { promises as fs } from 'node:fs';
13
+ import path from 'node:path';
14
+ import process from 'node:process';
15
+ import { createSmartEditLogger } from './util/logging.js';
16
+ import { SMART_EDIT_DASHBOARD_DIR } from './constants.js';
17
+ import { getInstances, DEFAULT_DASHBOARD_PORT } from './instance-registry.js';
18
+ const { logger } = createSmartEditLogger({ name: 'smart-edit.standalone-dashboard', emitToConsole: true, level: 'info' });
19
+ const DASHBOARD_HOST = '127.0.0.1';
20
+ const CONTENT_TYPE_BY_EXTENSION = {
21
+ '.html': 'text/html; charset=utf-8',
22
+ '.js': 'application/javascript; charset=utf-8',
23
+ '.css': 'text/css; charset=utf-8',
24
+ '.png': 'image/png',
25
+ '.json': 'application/json; charset=utf-8',
26
+ '.ico': 'image/x-icon'
27
+ };
28
+ export class StandaloneDashboardServer {
29
+ server = null;
30
+ listeningPort = null;
31
+ requestedPort;
32
+ constructor(options = {}) {
33
+ this.requestedPort = options.port ?? DEFAULT_DASHBOARD_PORT;
34
+ }
35
+ async start() {
36
+ if (this.server && this.listeningPort !== null) {
37
+ return this.listeningPort;
38
+ }
39
+ const { server, port } = await this.startServer();
40
+ this.server = server;
41
+ this.listeningPort = port;
42
+ logger.info(`Smart-Edit standalone dashboard listening on http://${DASHBOARD_HOST}:${port}/dashboard/`);
43
+ return port;
44
+ }
45
+ stop() {
46
+ if (this.server) {
47
+ this.server.close((error) => {
48
+ if (error) {
49
+ logger.warn('Failed to stop standalone dashboard server cleanly.', error);
50
+ }
51
+ });
52
+ this.server = null;
53
+ this.listeningPort = null;
54
+ }
55
+ }
56
+ getPort() {
57
+ return this.listeningPort;
58
+ }
59
+ async startServer() {
60
+ let candidatePort = this.requestedPort;
61
+ let lastError = null;
62
+ while (candidatePort <= 65535) {
63
+ const server = createServer((req, res) => {
64
+ void this.handleRequest(req, res);
65
+ });
66
+ try {
67
+ const port = await this.listenOnPort(server, candidatePort);
68
+ return { server, port };
69
+ }
70
+ catch (error) {
71
+ lastError = error;
72
+ try {
73
+ server.close();
74
+ }
75
+ catch {
76
+ // ignore close errors
77
+ }
78
+ if (lastError && (lastError.code === 'EADDRINUSE' || lastError.code === 'EACCES')) {
79
+ candidatePort += 1;
80
+ continue;
81
+ }
82
+ logger.error('Failed to start standalone dashboard server.', lastError ?? undefined);
83
+ break;
84
+ }
85
+ }
86
+ throw new Error(lastError?.message ?? 'Unable to start standalone dashboard server; no available ports.');
87
+ }
88
+ listenOnPort(server, port) {
89
+ return new Promise((resolve, reject) => {
90
+ const onError = (error) => {
91
+ cleanup();
92
+ reject(error);
93
+ };
94
+ const onListening = () => {
95
+ const address = server.address();
96
+ cleanup();
97
+ if (address && typeof address === 'object') {
98
+ resolve(address.port);
99
+ }
100
+ else {
101
+ resolve(port);
102
+ }
103
+ };
104
+ const cleanup = () => {
105
+ server.off('error', onError);
106
+ server.off('listening', onListening);
107
+ };
108
+ server.once('error', onError);
109
+ server.once('listening', onListening);
110
+ server.listen({ port, host: DASHBOARD_HOST, exclusive: true });
111
+ });
112
+ }
113
+ async handleRequest(req, res) {
114
+ const method = req.method?.toUpperCase() ?? 'GET';
115
+ const url = parseUrl(req.url ?? '/', true);
116
+ const pathname = url.pathname ?? '/';
117
+ // Add CORS headers for cross-origin requests from dashboard UI to MCP instances
118
+ res.setHeader('Access-Control-Allow-Origin', '*');
119
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');
120
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
121
+ if (method === 'OPTIONS') {
122
+ res.statusCode = 204;
123
+ res.end();
124
+ return;
125
+ }
126
+ try {
127
+ // Redirect root to dashboard
128
+ if (pathname === '/' || pathname === '') {
129
+ res.statusCode = 302;
130
+ res.setHeader('Location', '/dashboard/');
131
+ res.end();
132
+ return;
133
+ }
134
+ if (pathname.startsWith('/dashboard')) {
135
+ if (method !== 'GET') {
136
+ this.respondMethodNotAllowed(res);
137
+ return;
138
+ }
139
+ await this.serveDashboardAsset(pathname, res);
140
+ return;
141
+ }
142
+ // API endpoints for multi-instance mode
143
+ if (pathname === '/api/instances') {
144
+ if (method !== 'GET') {
145
+ this.respondMethodNotAllowed(res);
146
+ return;
147
+ }
148
+ this.handleGetInstances(res);
149
+ return;
150
+ }
151
+ this.respondNotFound(res);
152
+ }
153
+ catch (error) {
154
+ logger.error('Standalone dashboard request failed.', error instanceof Error ? error : undefined);
155
+ this.sendJson(res, 500, { error: 'Internal server error' });
156
+ }
157
+ }
158
+ handleGetInstances(res) {
159
+ const instances = getInstances();
160
+ this.sendJson(res, 200, { instances });
161
+ }
162
+ async serveDashboardAsset(pathname, res) {
163
+ let relativePath = pathname.replace(/^\/dashboard\/?/, '');
164
+ // Handle directory requests
165
+ if (relativePath === '' || relativePath.endsWith('/')) {
166
+ relativePath = relativePath + 'index.html';
167
+ }
168
+ const resolvedPath = path.resolve(SMART_EDIT_DASHBOARD_DIR, decodeURIComponent(relativePath));
169
+ if (!resolvedPath.startsWith(path.resolve(SMART_EDIT_DASHBOARD_DIR))) {
170
+ this.respondNotFound(res);
171
+ return;
172
+ }
173
+ try {
174
+ const file = await fs.readFile(resolvedPath);
175
+ const ext = path.extname(resolvedPath).toLowerCase();
176
+ const contentType = CONTENT_TYPE_BY_EXTENSION[ext] ?? 'application/octet-stream';
177
+ res.statusCode = 200;
178
+ res.setHeader('Content-Type', contentType);
179
+ res.setHeader('Content-Length', file.length);
180
+ res.end(file);
181
+ }
182
+ catch (error) {
183
+ if (error.code === 'ENOENT') {
184
+ this.respondNotFound(res);
185
+ return;
186
+ }
187
+ throw error;
188
+ }
189
+ }
190
+ respondNotFound(res) {
191
+ res.statusCode = 404;
192
+ res.end('Not found');
193
+ }
194
+ respondMethodNotAllowed(res) {
195
+ res.statusCode = 405;
196
+ res.end('Method not allowed');
197
+ }
198
+ sendJson(res, statusCode, payload) {
199
+ const body = JSON.stringify(payload);
200
+ res.statusCode = statusCode;
201
+ res.setHeader('Content-Type', 'application/json; charset=utf-8');
202
+ res.setHeader('Content-Length', Buffer.byteLength(body, 'utf-8'));
203
+ res.end(body);
204
+ }
205
+ }
206
+ /**
207
+ * Start a standalone dashboard server and wait for shutdown signal.
208
+ */
209
+ export async function runStandaloneDashboard(options = {}) {
210
+ const server = new StandaloneDashboardServer(options);
211
+ const port = await server.start();
212
+ console.log(`Smart-Edit Dashboard is running at: http://127.0.0.1:${port}/dashboard/`);
213
+ console.log('Press Ctrl+C to stop.');
214
+ await new Promise((resolve) => {
215
+ const shutdown = () => {
216
+ console.log('\nShutting down dashboard...');
217
+ server.stop();
218
+ resolve();
219
+ };
220
+ process.once('SIGINT', shutdown);
221
+ process.once('SIGTERM', shutdown);
222
+ });
223
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nogataka/smart-edit",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Smart Edit is a tool for editing code with AI.",
5
5
  "private": false,
6
6
  "license": "MIT",