@nogataka/smart-edit 1.0.1 → 1.0.2

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;gap:5px;background-color:var(--bg-secondary);border:1px solid var(--border-color);border-radius:4px;padding:6px 12px;cursor:pointer;transition:background-color .3s ease,border-color .3s ease}.theme-toggle:hover{background-color:var(--border-color)}.theme-toggle .icon{font-size:16px}.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;align-items:center;justify-content:center;height:200px;color:var(--text-muted);font-style:italic}@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-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}}
@@ -2,6 +2,8 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/png" href="/dashboard/logo.png" />
6
+ <link rel="apple-touch-icon" href="/dashboard/logo.png" />
5
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
8
  <title>Smart Edit Dashboard</title>
7
9
  <script type="module" crossorigin src="/dashboard/dashboard.js"></script>
@@ -1,12 +1,16 @@
1
1
  import { Tool } from './tools_base.js';
2
2
  export declare class CheckOnboardingPerformedTool extends Tool {
3
- static readonly description = "Checks whether project onboarding was already performed.";
3
+ static readonly description = "Checks whether project onboarding was already performed and if there are significant changes since last onboarding.";
4
4
  apply(_args?: Record<string, unknown>): Promise<string>;
5
5
  }
6
6
  export declare class OnboardingTool extends Tool {
7
7
  static readonly description = "Provides onboarding instructions (project structure, essential tasks, etc.) when onboarding has not been performed.";
8
8
  apply(_args?: Record<string, unknown>): Promise<string>;
9
9
  }
10
+ export declare class CollectProjectSymbolsTool extends Tool {
11
+ static readonly description: string;
12
+ apply(args?: Record<string, unknown>): Promise<string>;
13
+ }
10
14
  export declare class ThinkAboutCollectedInformationTool extends Tool {
11
15
  static readonly description = "Encourages the agent to reflect on whether the gathered information is sufficient and relevant.";
12
16
  apply(_args?: Record<string, unknown>): Promise<string>;
@@ -1,6 +1,8 @@
1
1
  import os from 'node:os';
2
2
  import { Tool, ToolMarkerDoesNotRequireActiveProject, ToolMarkerOptional } from './tools_base.js';
3
- import { ListMemoriesTool } from './memory_tools.js';
3
+ import { ListMemoriesTool, ReadMemoryTool, WriteMemoryTool } from './memory_tools.js';
4
+ import { getCurrentCommit, hasSignificantChanges } from '../util/git.js';
5
+ const PROJECT_SYMBOLS_MEMORY = 'project-symbols';
4
6
  function ensureString(value) {
5
7
  if (typeof value === 'string') {
6
8
  return value;
@@ -76,7 +78,7 @@ async function callAgentSystemPrompt(agent) {
76
78
  throw new Error('Agent does not implement a system prompt creation method.');
77
79
  }
78
80
  export class CheckOnboardingPerformedTool extends Tool {
79
- static description = 'Checks whether project onboarding was already performed.';
81
+ static description = 'Checks whether project onboarding was already performed and if there are significant changes since last onboarding.';
80
82
  async apply(_args = {}) {
81
83
  const listTool = getToolInstance(this.agent, ListMemoriesTool);
82
84
  const raw = await Promise.resolve(listTool.apply());
@@ -95,13 +97,47 @@ export class CheckOnboardingPerformedTool extends Tool {
95
97
  return ('Onboarding not performed yet (no memories available). ' +
96
98
  'You should perform onboarding by calling the `onboarding` tool before proceeding with the task.');
97
99
  }
100
+ // Check for significant changes since last onboarding
101
+ let significantChangesInfo = '';
102
+ if (parsed.includes(PROJECT_SYMBOLS_MEMORY)) {
103
+ try {
104
+ const readTool = getToolInstance(this.agent, ReadMemoryTool);
105
+ const memoryContent = await Promise.resolve(readTool.apply({ memory_file_name: PROJECT_SYMBOLS_MEMORY }));
106
+ const projectSymbols = JSON.parse(ensureString(memoryContent));
107
+ const lastCommit = projectSymbols.lastCommit;
108
+ if (lastCommit) {
109
+ const currentCommit = await getCurrentCommit();
110
+ if (currentCommit && currentCommit !== lastCommit) {
111
+ const changeInfo = await hasSignificantChanges(lastCommit);
112
+ if (changeInfo.significant) {
113
+ significantChangesInfo = [
114
+ '',
115
+ '## IMPORTANT: Significant Changes Detected',
116
+ '',
117
+ `Since your last onboarding (commit: ${lastCommit.substring(0, 7)}), there have been significant changes:`,
118
+ changeInfo.summary,
119
+ '',
120
+ 'Consider re-running onboarding to refresh the project-symbols memory.',
121
+ 'Use the `onboarding` tool to update your knowledge of the codebase.',
122
+ ''
123
+ ].join('\n');
124
+ }
125
+ }
126
+ }
127
+ }
128
+ catch (error) {
129
+ // If we can't read the memory or parse it, just continue without the check
130
+ const message = error instanceof Error ? error.message : String(error);
131
+ significantChangesInfo = `\n(Note: Could not check for changes: ${message})\n`;
132
+ }
133
+ }
98
134
  const lines = [
99
135
  'The onboarding was already performed, below is the list of available memories.',
100
136
  'Do not read them immediately, just remember that they exist and that you can read them later, if it is necessary',
101
137
  'for the current task.',
102
138
  'Some memories may be based on previous conversations, others may be general for the current project.',
103
139
  'You should be able to tell which one you need based on the name of the memory.',
104
- '',
140
+ significantChangesInfo,
105
141
  JSON.stringify(parsed)
106
142
  ];
107
143
  return lines.join('\n');
@@ -115,6 +151,43 @@ export class OnboardingTool extends Tool {
115
151
  return result;
116
152
  }
117
153
  }
154
+ export class CollectProjectSymbolsTool extends Tool {
155
+ static description = 'Collects and saves project symbols (utilities, components, dependencies) to the project-symbols memory. ' +
156
+ 'Call this after onboarding to enable duplicate detection features.';
157
+ async apply(args = {}) {
158
+ const { utility_dirs = [], common_components = [], dependencies = {} } = args;
159
+ // Get current git commit
160
+ const currentCommit = await getCurrentCommit();
161
+ // Build the project symbols memory content
162
+ const projectSymbols = {
163
+ lastCommit: currentCommit ?? 'unknown',
164
+ lastUpdated: new Date().toISOString(),
165
+ dependencies,
166
+ utilityDirs: utility_dirs,
167
+ commonComponents: common_components
168
+ };
169
+ // Save to memory
170
+ const writeTool = getToolInstance(this.agent, WriteMemoryTool);
171
+ const memoryContent = JSON.stringify(projectSymbols, null, 2);
172
+ await Promise.resolve(writeTool.apply({
173
+ memory_name: PROJECT_SYMBOLS_MEMORY,
174
+ content: memoryContent
175
+ }));
176
+ const lines = [
177
+ `Project symbols saved to memory: ${PROJECT_SYMBOLS_MEMORY}`,
178
+ '',
179
+ `- Commit: ${projectSymbols.lastCommit}`,
180
+ `- Updated: ${projectSymbols.lastUpdated}`,
181
+ `- Utility directories: ${utility_dirs.length > 0 ? utility_dirs.join(', ') : 'none specified'}`,
182
+ `- Common components: ${common_components.length > 0 ? common_components.join(', ') : 'none specified'}`,
183
+ `- Dependencies tracked: ${Object.keys(dependencies).length}`,
184
+ '',
185
+ 'This information will be used for duplicate detection in careful-editor mode.',
186
+ 'The system will alert you when significant changes occur since this onboarding.'
187
+ ];
188
+ return lines.join('\n');
189
+ }
190
+ }
118
191
  export class ThinkAboutCollectedInformationTool extends Tool {
119
192
  static description = 'Encourages the agent to reflect on whether the gathered information is sufficient and relevant.';
120
193
  async apply(_args = {}) {
@@ -4,8 +4,38 @@ export interface GitStatus {
4
4
  hasStagedUncommittedChanges: boolean;
5
5
  hasUntrackedFiles: boolean;
6
6
  }
7
+ export interface GitDiffStats {
8
+ filesChanged: number;
9
+ insertions: number;
10
+ deletions: number;
11
+ newFiles: number;
12
+ hasNewInSrc: boolean;
13
+ }
7
14
  export interface GetGitStatusOptions {
8
15
  cwd?: string;
9
16
  env?: NodeJS.ProcessEnv;
10
17
  }
11
18
  export declare function getGitStatus(options?: GetGitStatusOptions): Promise<GitStatus | null>;
19
+ /**
20
+ * Get the current HEAD commit hash.
21
+ */
22
+ export declare function getCurrentCommit(options?: GetGitStatusOptions): Promise<string | null>;
23
+ /**
24
+ * Get diff statistics between two commits.
25
+ */
26
+ export declare function getGitDiffStats(fromCommit: string, toCommit?: string, options?: GetGitStatusOptions): Promise<GitDiffStats | null>;
27
+ /**
28
+ * Check if the new files list contains files in src/ directory.
29
+ */
30
+ export declare function hasNewFilesInSrc(fromCommit: string, toCommit?: string, options?: GetGitStatusOptions): Promise<boolean>;
31
+ /**
32
+ * Determine if there are significant changes since the last commit.
33
+ * Significant changes are defined as:
34
+ * - More than 10 files changed
35
+ * - More than 5 new files
36
+ * - Any new files in src/ directory
37
+ */
38
+ export declare function hasSignificantChanges(lastCommit: string, options?: GetGitStatusOptions): Promise<{
39
+ significant: boolean;
40
+ summary: string;
41
+ }>;
@@ -35,3 +35,121 @@ async function hasGitOutput(args, options) {
35
35
  const output = await runGitCommand(args, options);
36
36
  return output.length > 0;
37
37
  }
38
+ /**
39
+ * Get the current HEAD commit hash.
40
+ */
41
+ export async function getCurrentCommit(options = {}) {
42
+ try {
43
+ return await runGitCommand(['rev-parse', 'HEAD'], options);
44
+ }
45
+ catch (error) {
46
+ gitLogger.debug('Failed to get current commit', { error });
47
+ return null;
48
+ }
49
+ }
50
+ /**
51
+ * Parse git diff --stat output to extract statistics.
52
+ */
53
+ function parseDiffStatOutput(output) {
54
+ const lines = output.trim().split('\n').filter((line) => line.length > 0);
55
+ let filesChanged = 0;
56
+ let insertions = 0;
57
+ let deletions = 0;
58
+ let newFiles = 0;
59
+ let hasNewInSrc = false;
60
+ const filePattern = /^\s*(.+?)\s*\|\s*(\d+)/;
61
+ const summaryPattern = /(\d+)\s+files?\s+changed(?:,\s+(\d+)\s+insertions?\(\+\))?(?:,\s+(\d+)\s+deletions?\(-\))?/;
62
+ const plusPattern = /\+/g;
63
+ const minusPattern = /-/g;
64
+ // Parse individual file lines
65
+ for (const line of lines) {
66
+ // Match lines like: "src/file.ts | 10 ++++----"
67
+ const fileMatch = filePattern.exec(line);
68
+ if (fileMatch) {
69
+ filesChanged++;
70
+ const filePath = fileMatch[1].trim();
71
+ // Check if it's a new file in src/
72
+ if (filePath.startsWith('src/') && line.includes('(new)')) {
73
+ newFiles++;
74
+ hasNewInSrc = true;
75
+ }
76
+ // Count insertions and deletions from + and - symbols
77
+ const plusMatches = line.match(plusPattern);
78
+ const minusMatches = line.match(minusPattern);
79
+ insertions += plusMatches?.length ?? 0;
80
+ deletions += minusMatches?.length ?? 0;
81
+ }
82
+ // Parse the summary line: "3 files changed, 10 insertions(+), 5 deletions(-)"
83
+ const summaryMatch = summaryPattern.exec(line);
84
+ if (summaryMatch) {
85
+ filesChanged = parseInt(summaryMatch[1], 10);
86
+ if (summaryMatch[2]) {
87
+ insertions = parseInt(summaryMatch[2], 10);
88
+ }
89
+ if (summaryMatch[3]) {
90
+ deletions = parseInt(summaryMatch[3], 10);
91
+ }
92
+ }
93
+ }
94
+ return { filesChanged, insertions, deletions, newFiles, hasNewInSrc };
95
+ }
96
+ /**
97
+ * Get diff statistics between two commits.
98
+ */
99
+ export async function getGitDiffStats(fromCommit, toCommit = 'HEAD', options = {}) {
100
+ try {
101
+ const output = await runGitCommand(['diff', '--stat', `${fromCommit}..${toCommit}`], options);
102
+ return parseDiffStatOutput(output);
103
+ }
104
+ catch (error) {
105
+ gitLogger.debug('Failed to get git diff stats', { error, fromCommit, toCommit });
106
+ return null;
107
+ }
108
+ }
109
+ /**
110
+ * Check if the new files list contains files in src/ directory.
111
+ */
112
+ export async function hasNewFilesInSrc(fromCommit, toCommit = 'HEAD', options = {}) {
113
+ try {
114
+ const output = await runGitCommand(['diff', '--name-status', '--diff-filter=A', `${fromCommit}..${toCommit}`], options);
115
+ const lines = output.trim().split('\n').filter((line) => line.length > 0);
116
+ return lines.some((line) => {
117
+ const parts = line.split('\t');
118
+ const filePath = parts[1] || '';
119
+ return filePath.startsWith('src/');
120
+ });
121
+ }
122
+ catch (error) {
123
+ gitLogger.debug('Failed to check for new files in src/', { error });
124
+ return false;
125
+ }
126
+ }
127
+ /**
128
+ * Determine if there are significant changes since the last commit.
129
+ * Significant changes are defined as:
130
+ * - More than 10 files changed
131
+ * - More than 5 new files
132
+ * - Any new files in src/ directory
133
+ */
134
+ export async function hasSignificantChanges(lastCommit, options = {}) {
135
+ const diffStats = await getGitDiffStats(lastCommit, 'HEAD', options);
136
+ if (!diffStats) {
137
+ return { significant: false, summary: 'Unable to determine changes' };
138
+ }
139
+ const hasNewInSrc = await hasNewFilesInSrc(lastCommit, 'HEAD', options);
140
+ const reasons = [];
141
+ if (diffStats.filesChanged > 10) {
142
+ reasons.push(`${diffStats.filesChanged} files changed`);
143
+ }
144
+ if (diffStats.newFiles > 5) {
145
+ reasons.push(`${diffStats.newFiles} new files`);
146
+ }
147
+ if (hasNewInSrc) {
148
+ reasons.push('new files in src/ directory');
149
+ }
150
+ const significant = reasons.length > 0;
151
+ const summary = significant
152
+ ? `Significant changes detected: ${reasons.join(', ')}`
153
+ : `Minor changes: ${diffStats.filesChanged} files, +${diffStats.insertions}/-${diffStats.deletions}`;
154
+ return { significant, summary };
155
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nogataka/smart-edit",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Smart Edit is a tool for editing code with AI.",
5
5
  "private": false,
6
6
  "license": "MIT",