claude-home 1.7.2 → 1.7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-home",
3
- "version": "1.7.2",
3
+ "version": "1.7.4",
4
4
  "description": "Web dashboard for Claude Code — browse sessions, manage skills, hooks, commands, and agents",
5
5
  "main": "server.js",
6
6
  "bin": {
package/public/index.html CHANGED
@@ -53,7 +53,44 @@
53
53
  display: flex;
54
54
  flex-direction: column;
55
55
  overflow: hidden;
56
+ position: relative;
56
57
  }
58
+ .sidebar.nav-animating { transition: width 0.18s ease, min-width 0.18s ease; }
59
+ .nav-resize-handle {
60
+ position: absolute;
61
+ top: 0; right: -3px;
62
+ width: 6px; height: 100%;
63
+ cursor: col-resize;
64
+ z-index: 10;
65
+ }
66
+ .nav-resize-handle:hover, .nav-resize-handle.dragging { background: var(--blue); opacity: 0.35; }
67
+ .nav-collapse-btn {
68
+ margin-left: auto;
69
+ background: none;
70
+ border: none;
71
+ cursor: pointer;
72
+ color: var(--ink-3);
73
+ padding: 2px 4px;
74
+ border-radius: 4px;
75
+ display: flex;
76
+ align-items: center;
77
+ flex-shrink: 0;
78
+ }
79
+ .nav-collapse-btn:hover { color: var(--ink); background: var(--canvas); }
80
+ /* ── Icon-only mode ──────────────────────────────────── */
81
+ .nav-icon-only .brand { padding: 16px 0; justify-content: center; gap: 0; }
82
+ .nav-icon-only .brand > :not(.brand-mark) { display: none !important; }
83
+ .nav-icon-only .brand-mark { cursor: pointer; }
84
+ .nav-icon-only .brand-mark:hover { opacity: 0.75; }
85
+ .nav-icon-only .nav-section-label { display: none !important; }
86
+ .nav-icon-only .nav-divider { margin: 4px 8px; }
87
+ .nav-icon-only .nav-item { padding: 9px 0; justify-content: center; gap: 0; border-left-width: 0; }
88
+ .nav-icon-only .nav-item.active { background: var(--canvas); }
89
+ .nav-icon-only .nav-item .nav-icon { width: 44px; height: 16px; }
90
+ .nav-icon-only .nav-text { display: none !important; }
91
+ .nav-icon-only .nav-count { display: none !important; }
92
+ .nav-icon-only .live-dot { display: none !important; }
93
+ .nav-icon-only .sidebar-footer { display: none !important; }
57
94
 
58
95
  .brand {
59
96
  padding: 20px 18px 16px;
@@ -741,6 +778,8 @@
741
778
  margin-top: 6px;
742
779
  opacity: 0;
743
780
  transition: opacity 0.15s;
781
+ white-space: nowrap;
782
+ flex-wrap: nowrap;
744
783
  }
745
784
  .message:hover .message-footer { opacity: 1; }
746
785
 
@@ -1992,9 +2031,10 @@
1992
2031
  <body x-data="app()" x-init="init()">
1993
2032
 
1994
2033
  <!-- ── Sidebar ── -->
1995
- <aside class="sidebar">
2034
+ <aside class="sidebar" :class="{ 'nav-icon-only': navWidth <= 56 }" :style="`width:${navWidth}px;min-width:${navWidth}px`">
2035
+ <div class="nav-resize-handle" :class="{ dragging: _navDragging }" @mousedown.prevent="startNavResize($event)"></div>
1996
2036
  <div class="brand">
1997
- <div class="brand-mark">
2037
+ <div class="brand-mark" @click="if(navWidth <= 56) toggleNav()" :style="navWidth <= 56 ? 'cursor:pointer' : ''">
1998
2038
  <svg width="12" height="12" viewBox="0 0 12 12" fill="white">
1999
2039
  <rect x="0" y="0" width="5" height="5"/>
2000
2040
  <rect x="7" y="0" width="5" height="5"/>
@@ -2002,10 +2042,15 @@
2002
2042
  <circle cx="9.5" cy="9.5" r="2.5"/>
2003
2043
  </svg>
2004
2044
  </div>
2005
- <span style="display:flex;flex-direction:column;line-height:1">
2006
- <span class="brand-name">CLAUDE HOME</span>
2007
- <span style="font-size:9px;font-weight:400;color:var(--ink-3);letter-spacing:0.02em" x-text="status?.appVersion ? 'v'+status.appVersion : ''"></span>
2008
- </span>
2045
+ <span class="nav-text" style="display:flex;flex-direction:column;line-height:1">
2046
+ <span class="brand-name">CLAUDE HOME</span>
2047
+ <span style="font-size:9px;font-weight:400;color:var(--ink-3);letter-spacing:0.02em" x-text="status?.appVersion ? 'v'+status.appVersion : ''"></span>
2048
+ </span>
2049
+ <button class="nav-collapse-btn" @click="toggleNav()" :title="navWidth <= 56 ? 'Expandir sidebar' : 'Colapsar sidebar'">
2050
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.5">
2051
+ <polyline :points="navWidth <= 56 ? '5,2 10,7 5,12' : '9,2 4,7 9,12'"/>
2052
+ </svg>
2053
+ </button>
2009
2054
  </div>
2010
2055
 
2011
2056
  <div class="nav-section">
@@ -2016,18 +2061,12 @@
2016
2061
  <line x1="5" y1="6" x2="11" y2="6"/><line x1="5" y1="10" x2="8.5" y2="10"/>
2017
2062
  </svg>
2018
2063
  </span>
2019
- Sessions
2064
+ <span class="nav-text">Sessions</span>
2020
2065
  <template x-if="activeSessions.length > 0">
2021
2066
  <span class="live-dot" title="Active session"></span>
2022
2067
  </template>
2023
2068
  <span class="nav-count" x-show="activeSessions.length === 0" x-text="totalSessions"></span>
2024
2069
  </div>
2025
- <!-- Active project name under Sessions -->
2026
- <template x-if="activeSessions.length > 0">
2027
- <div @click="view='sessions';selectedSession=null" style="padding:0 18px 8px 41px;cursor:pointer;margin-top:-4px">
2028
- <span style="font-size:10.5px;color:var(--red);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;max-width:160px" x-text="(activeSessions[0].projectPath ? shortProjectName(activeSessions[0].projectPath) : null) || activeSessions[0].projectDir.replace(/^-/,'').replace(/--/g,'/').split('/').pop()"></span>
2029
- </div>
2030
- </template>
2031
2070
  <div class="nav-item" :class="{ active: view === 'plans' }" @click="view='plans';selectedSession=null;loadPlans()">
2032
2071
  <span class="nav-icon">
2033
2072
  <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke-width="1.5">
@@ -2035,20 +2074,9 @@
2035
2074
  <line x1="5" y1="6" x2="11" y2="6"/><line x1="5" y1="9" x2="11" y2="9"/><line x1="5" y1="12" x2="8" y2="12"/>
2036
2075
  </svg>
2037
2076
  </span>
2038
- Plans
2077
+ <span class="nav-text">Plans</span>
2039
2078
  <span class="nav-count" x-show="plans.length>0" x-text="plans.length"></span>
2040
2079
  </div>
2041
- <div class="nav-item" :class="{ active: view === 'notes' }" x-show="showNotes" @click="view='notes';selectedSession=null;loadPersonalNotes()">
2042
- <span class="nav-icon">
2043
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke-width="1.5" stroke="currentColor">
2044
- <path d="M3 2h8l3 3v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1z"/>
2045
- <polyline points="11 2 11 5 14 5"/>
2046
- <line x1="5" y1="7" x2="11" y2="7"/><line x1="5" y1="10" x2="9" y2="10"/>
2047
- </svg>
2048
- </span>
2049
- Journal
2050
- <span class="nav-count" x-show="personalNotes.length>0" x-text="personalNotes.length"></span>
2051
- </div>
2052
2080
  </div>
2053
2081
  <div class="nav-divider"></div>
2054
2082
  <div class="nav-section">
@@ -2061,7 +2089,7 @@
2061
2089
  <circle cx="4" cy="5" r="1.5" stroke-dasharray="2,1"/>
2062
2090
  </svg>
2063
2091
  </span>
2064
- Agents
2092
+ <span class="nav-text">Agents</span>
2065
2093
  <span class="nav-count" x-show="agents.length>0" x-text="agents.length"></span>
2066
2094
  </div>
2067
2095
  <div class="nav-item" :class="{ active: view === 'skills' }" @click="view='skills';selectedSession=null;loadTools()">
@@ -2070,7 +2098,7 @@
2070
2098
  <path d="M10 2L6 9h4l-2 5L14 7h-4z"/>
2071
2099
  </svg>
2072
2100
  </span>
2073
- Skills
2101
+ <span class="nav-text">Skills</span>
2074
2102
  <span class="nav-count" x-show="toolSkills.length>0" x-text="toolSkills.length"></span>
2075
2103
  </div>
2076
2104
  <div class="nav-item" :class="{ active: view === 'commands' }" @click="view='commands';selectedSession=null;loadTools()">
@@ -2080,7 +2108,7 @@
2080
2108
  <polyline points="5,7 7,9 5,11"/><line x1="8" y1="11" x2="12" y2="11"/>
2081
2109
  </svg>
2082
2110
  </span>
2083
- Commands
2111
+ <span class="nav-text">Commands</span>
2084
2112
  <span class="nav-count" x-show="toolCommands.length>0" x-text="toolCommands.length"></span>
2085
2113
  </div>
2086
2114
  </div>
@@ -2093,7 +2121,7 @@
2093
2121
  <line x1="6" y1="7" x2="10" y2="7"/><line x1="6" y1="10" x2="10" y2="10"/>
2094
2122
  </svg>
2095
2123
  </span>
2096
- Memory
2124
+ <span class="nav-text">Memory</span>
2097
2125
  <span class="nav-count" x-show="memoryFiles.length>0" x-text="memoryFiles.length"></span>
2098
2126
  </div>
2099
2127
  <div class="nav-item" :class="{ active: view === 'instructions' }" @click="view='instructions';selectedSession=null;loadConfig()">
@@ -2102,7 +2130,7 @@
2102
2130
  <path d="M3 2h10v12H3z"/><line x1="5.5" y1="5.5" x2="10.5" y2="5.5"/><line x1="5.5" y1="8" x2="10.5" y2="8"/><line x1="5.5" y1="10.5" x2="8.5" y2="10.5"/>
2103
2131
  </svg>
2104
2132
  </span>
2105
- Instructions
2133
+ <span class="nav-text">Instructions</span>
2106
2134
  </div>
2107
2135
  <div class="nav-item" :class="{ active: view === 'permissions' }" @click="view='permissions';selectedSession=null;loadConfig()">
2108
2136
  <span class="nav-icon">
@@ -2110,7 +2138,7 @@
2110
2138
  <rect x="4" y="7" width="8" height="7" rx="1"/><path d="M5.5 7V5a2.5 2.5 0 0 1 5 0v2"/>
2111
2139
  </svg>
2112
2140
  </span>
2113
- Permissions
2141
+ <span class="nav-text">Permissions</span>
2114
2142
  </div>
2115
2143
  <div class="nav-item" :class="{ active: view === 'hooks' }" @click="view='hooks';selectedSession=null;loadConfig()">
2116
2144
  <span class="nav-icon">
@@ -2120,7 +2148,7 @@
2120
2148
  <path d="M2.5 5a8 8 0 0 1 11 0"/>
2121
2149
  </svg>
2122
2150
  </span>
2123
- Hooks
2151
+ <span class="nav-text">Hooks</span>
2124
2152
  </div>
2125
2153
  </div>
2126
2154
  <div class="nav-divider"></div>
@@ -2133,16 +2161,19 @@
2133
2161
  <line x1="1.5" y1="8" x2="5" y2="8"/><line x1="11" y1="8" x2="14.5" y2="8"/>
2134
2162
  </svg>
2135
2163
  </span>
2136
- Config
2164
+ <span class="nav-text">Config</span>
2137
2165
  </div>
2138
2166
  </div>
2139
2167
 
2140
- <template x-if="showToday">
2168
+ <template x-if="showToday || showInsights || showNotes">
2141
2169
  <div>
2142
2170
  <div class="nav-divider"></div>
2143
- <div class="nav-section-label">Widgets</div>
2144
- <div class="nav-section">
2145
- <div class="nav-item nav-widget" :class="{ active: view === 'today' }" @click="view='today';selectedSession=null;loadToday()">
2171
+ <div class="nav-section-label" @click="widgetsOpen=!widgetsOpen;localStorage.setItem('cs:widgetsOpen',widgetsOpen)" style="cursor:pointer;display:flex;align-items:center;justify-content:space-between;padding-right:12px;user-select:none">
2172
+ Widgets
2173
+ <svg :style="widgetsOpen ? '' : 'transform:rotate(-90deg)'" style="transition:transform 0.15s" width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5"><polyline points="2,3 5,7 8,3"/></svg>
2174
+ </div>
2175
+ <div class="nav-section" x-show="widgetsOpen || navWidth <= 56">
2176
+ <div x-show="showToday" class="nav-item nav-widget" :class="{ active: view === 'today' }" @click="view='today';selectedSession=null;loadToday()">
2146
2177
  <span class="nav-icon">
2147
2178
  <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5">
2148
2179
  <rect x="2" y="2" width="12" height="12" rx="1"/>
@@ -2151,9 +2182,30 @@
2151
2182
  <text x="5" y="13" font-size="5" fill="currentColor" stroke="none" font-weight="bold" x-text="new Date().getDate()"></text>
2152
2183
  </svg>
2153
2184
  </span>
2154
- Today
2185
+ <span class="nav-text">Today</span>
2155
2186
  <span class="nav-count" x-show="todayData && todayData.tasks.filter(t=>!t.done).length > 0" x-text="todayData ? todayData.tasks.filter(t=>!t.done).length : ''"></span>
2156
2187
  </div>
2188
+ <div x-show="showInsights" class="nav-item nav-widget" :class="{ active: view === 'dashboard' }" @click="view='dashboard';selectedSession=null;loadStats();loadInsights()">
2189
+ <span class="nav-icon">
2190
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5">
2191
+ <rect x="2" y="8" width="3" height="6" rx="0.5"/>
2192
+ <rect x="6.5" y="5" width="3" height="9" rx="0.5"/>
2193
+ <rect x="11" y="2" width="3" height="12" rx="0.5"/>
2194
+ </svg>
2195
+ </span>
2196
+ <span class="nav-text">Analytics</span>
2197
+ </div>
2198
+ <div x-show="showNotes" class="nav-item nav-widget" :class="{ active: view === 'notes' }" @click="view='notes';selectedSession=null;loadPersonalNotes()">
2199
+ <span class="nav-icon">
2200
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke-width="1.5" stroke="currentColor">
2201
+ <path d="M3 2h8l3 3v9a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1z"/>
2202
+ <polyline points="11 2 11 5 14 5"/>
2203
+ <line x1="5" y1="7" x2="11" y2="7"/><line x1="5" y1="10" x2="9" y2="10"/>
2204
+ </svg>
2205
+ </span>
2206
+ <span class="nav-text">Journal</span>
2207
+ <span class="nav-count" x-show="personalNotes.length>0" x-text="personalNotes.length"></span>
2208
+ </div>
2157
2209
  </div>
2158
2210
  </div>
2159
2211
  </template>
@@ -2789,15 +2841,6 @@
2789
2841
  </template>
2790
2842
  <template x-if="sessionSummaries[s.sessionId]">
2791
2843
  <div style="display:flex;flex-direction:column;gap:8px">
2792
- <!-- Tool counts -->
2793
- <template x-if="Object.keys(sessionSummaries[s.sessionId].toolCounts).length > 0">
2794
- <div style="display:flex;flex-wrap:wrap;gap:5px;align-items:center">
2795
- <span style="font-size:10.5px;color:var(--ink-3);margin-right:2px">Tools</span>
2796
- <template x-for="[tool, count] in Object.entries(sessionSummaries[s.sessionId].toolCounts).sort((a,b)=>b[1]-a[1]).slice(0,8)" :key="tool">
2797
- <span style="font-size:11px;padding:1px 6px;border-radius:4px;background:var(--bg-3,var(--rule));color:var(--ink-2)" x-text="tool + '×' + count"></span>
2798
- </template>
2799
- </div>
2800
- </template>
2801
2844
  <!-- Files touched -->
2802
2845
  <template x-if="sessionSummaries[s.sessionId].filesTouched.length > 0">
2803
2846
  <div>
@@ -3084,14 +3127,6 @@
3084
3127
  </template>
3085
3128
  </span>
3086
3129
  </template>
3087
- <!-- Tool count badges -->
3088
- <template x-if="sessionSummaries[selectedSession?.sessionId] && Object.keys(sessionSummaries[selectedSession.sessionId].toolCounts||{}).length">
3089
- <span style="display:flex;gap:4px;align-items:center;padding-left:8px;border-left:1px solid var(--rule)">
3090
- <template x-for="[tool,count] in Object.entries(sessionSummaries[selectedSession.sessionId].toolCounts).sort((a,b)=>b[1]-a[1]).slice(0,4)" :key="tool">
3091
- <span class="meta-tag" x-text="tool+'×'+count"></span>
3092
- </template>
3093
- </span>
3094
- </template>
3095
3130
  <!-- Bookmark navigation -->
3096
3131
  <template x-if="(sessionBookmarks[selectedSession?.sessionId]||[]).length > 0">
3097
3132
  <span style="display:flex;gap:3px;align-items:center;padding-left:8px;border-left:1px solid var(--rule)">
@@ -3170,14 +3205,6 @@
3170
3205
  </span>
3171
3206
  </template>
3172
3207
 
3173
- <!-- Tool feed -->
3174
- <template x-if="liveTools.length > 0">
3175
- <span style="display:flex;align-items:center;gap:4px;padding-left:12px;border-left:1px solid #F4D0D0">
3176
- <template x-for="(tool, ti) in liveTools" :key="ti">
3177
- <span class="live-tool-tag" x-text="tool"></span>
3178
- </template>
3179
- </span>
3180
- </template>
3181
3208
 
3182
3209
 
3183
3210
  </div>
@@ -3566,9 +3593,6 @@
3566
3593
  <template x-if="msg.message?.model">
3567
3594
  <span class="msg-meta" x-text="shortModelName(msg.message.model)"></span>
3568
3595
  </template>
3569
- <template x-if="msg.message?.usage">
3570
- <span class="msg-meta" x-text="'↑' + fmtNum(msg.message.usage.input_tokens) + ' ↓' + fmtNum(msg.message.usage.output_tokens)"></span>
3571
- </template>
3572
3596
  <span class="msg-meta" x-text="formatTime(msg.timestamp)"></span>
3573
3597
  <button class="bookmark-btn" :class="{bookmarked: isBookmarked(msg.uuid)}"
3574
3598
  @click.stop="toggleBookmark(msg)" title="Bookmark">
@@ -5296,6 +5320,16 @@
5296
5320
  <div style="font-size:11px;color:var(--ink-3);margin-top:3px">Show the Today task list in the navigation.</div>
5297
5321
  </div>
5298
5322
  </div>
5323
+ <div class="config-row">
5324
+ <div class="config-key">Show Analytics</div>
5325
+ <div class="config-val">
5326
+ <label style="display:flex;align-items:center;gap:6px;cursor:pointer">
5327
+ <input type="checkbox" x-model="showInsights" @change="localStorage.setItem('cs:showInsights', showInsights); if(!showInsights && view==='dashboard') view='sessions'; if(!showInsights && defaultView==='dashboard') { defaultView=''; localStorage.setItem('cs:defaultView','') }" />
5328
+ <span style="font-size:12px;color:var(--ink-2)" x-text="showInsights ? 'Visible' : 'Hidden'"></span>
5329
+ </label>
5330
+ <div style="font-size:11px;color:var(--ink-3);margin-top:3px">Show Analytics (Insights) in the Widgets section.</div>
5331
+ </div>
5332
+ </div>
5299
5333
  <div class="config-row">
5300
5334
  <div class="config-key">Show Journal</div>
5301
5335
  <div class="config-val">
@@ -5311,7 +5345,7 @@
5311
5345
  <div class="config-val" style="flex:1">
5312
5346
  <select class="settings-input" x-model="defaultView" @change="localStorage.setItem('cs:defaultView', defaultView)">
5313
5347
  <option value="">Remember last section</option>
5314
- <option value="dashboard">Insights</option>
5348
+ <template x-if="showInsights"><option value="dashboard">Analytics</option></template>
5315
5349
  <option value="sessions">Sessions</option>
5316
5350
  <template x-if="showToday"><option value="today">Today</option></template>
5317
5351
  <option value="plans">Plans</option>
@@ -6346,6 +6380,8 @@
6346
6380
  noteTagRenaming: false,
6347
6381
  noteTagRenameDraft: '',
6348
6382
  sidebarW: parseInt(localStorage.getItem('cm:sidebarW') || '260'),
6383
+ navWidth: parseInt(localStorage.getItem('cs:navWidth') || '224'),
6384
+ _navDragging: false,
6349
6385
  historyEntries: [],
6350
6386
  historyLoading: false,
6351
6387
  historySearch: '',
@@ -6489,6 +6525,8 @@
6489
6525
  knowledgeTab: 'memory',
6490
6526
  setupTab: 'commands',
6491
6527
  showToday: localStorage.getItem('cs:showToday') !== 'false',
6528
+ showInsights: localStorage.getItem('cs:showInsights') !== 'false',
6529
+ widgetsOpen: localStorage.getItem('cs:widgetsOpen') !== 'false',
6492
6530
  showNotes: localStorage.getItem('cs:showNotes') !== 'false',
6493
6531
  defaultView: localStorage.getItem('cs:defaultView') || '',
6494
6532
 
@@ -6547,6 +6585,7 @@
6547
6585
  const hiddenViews = [
6548
6586
  !this.showToday && 'today',
6549
6587
  !this.showNotes && 'notes',
6588
+ !this.showInsights && 'dashboard',
6550
6589
  ].filter(Boolean);
6551
6590
  if (startView && !hiddenViews.includes(startView)) this.view = startView;
6552
6591
  else if (hiddenViews.includes(startView)) this.view = 'sessions';
@@ -6910,14 +6949,16 @@
6910
6949
  const order = [];
6911
6950
  for (const d of diffs) {
6912
6951
  if (!fileMap.has(d.filePath)) {
6913
- fileMap.set(d.filePath, { filePath: d.filePath, tool: d.tool, totalAdded: 0, totalRemoved: 0, changes: [] });
6914
6952
  order.push(d.filePath);
6915
6953
  }
6916
- const e = fileMap.get(d.filePath);
6917
- e.totalAdded += d.added;
6918
- e.totalRemoved += d.removed;
6919
- if (d.tool === 'Write') e.tool = 'Write';
6920
- e.changes.push(d);
6954
+ // Siempre sobreescribir con el último cambio del fichero
6955
+ fileMap.set(d.filePath, {
6956
+ filePath: d.filePath,
6957
+ tool: d.tool,
6958
+ totalAdded: d.added,
6959
+ totalRemoved: d.removed,
6960
+ changes: [d],
6961
+ });
6921
6962
  }
6922
6963
  return order.map(k => fileMap.get(k));
6923
6964
  },
@@ -7404,6 +7445,46 @@
7404
7445
  document.addEventListener('mouseup', onUp);
7405
7446
  },
7406
7447
 
7448
+ toggleNav() {
7449
+ const el = document.querySelector('.sidebar');
7450
+ el.classList.add('nav-animating');
7451
+ if (this.navWidth <= 56) {
7452
+ this.navWidth = parseInt(localStorage.getItem('cs:navWidthFull') || '224');
7453
+ } else {
7454
+ localStorage.setItem('cs:navWidthFull', this.navWidth);
7455
+ this.navWidth = 44;
7456
+ }
7457
+ localStorage.setItem('cs:navWidth', this.navWidth);
7458
+ setTimeout(() => el.classList.remove('nav-animating'), 220);
7459
+ },
7460
+ startNavResize(e) {
7461
+ const startX = e.clientX;
7462
+ const startW = this.navWidth;
7463
+ this._navDragging = true;
7464
+ document.body.style.cursor = 'col-resize';
7465
+ document.body.style.userSelect = 'none';
7466
+ const ICON_W = 44, SNAP_IN = 80, MIN_FULL = 160, MAX_W = 400;
7467
+ const onMove = (ev) => {
7468
+ const w = startW + (ev.clientX - startX);
7469
+ if (w < SNAP_IN) {
7470
+ this.navWidth = ICON_W;
7471
+ } else {
7472
+ this.navWidth = Math.max(MIN_FULL, Math.min(MAX_W, w));
7473
+ }
7474
+ };
7475
+ const onUp = () => {
7476
+ this._navDragging = false;
7477
+ document.body.style.cursor = '';
7478
+ document.body.style.userSelect = '';
7479
+ if (this.navWidth > ICON_W) localStorage.setItem('cs:navWidthFull', this.navWidth);
7480
+ localStorage.setItem('cs:navWidth', this.navWidth);
7481
+ document.removeEventListener('mousemove', onMove);
7482
+ document.removeEventListener('mouseup', onUp);
7483
+ };
7484
+ document.addEventListener('mousemove', onMove);
7485
+ document.addEventListener('mouseup', onUp);
7486
+ },
7487
+
7407
7488
  async deleteSession() {
7408
7489
  if (!this.selectedSession) return;
7409
7490
  if (!confirm(`Delete session "${this.selectedSession.firstPrompt || this.selectedSession.sessionId}"? This cannot be undone.`)) return;
package/server.js CHANGED
@@ -2236,16 +2236,28 @@ app.post('/api/sessions/:project/:sessionId/snapshot', async (req, res) => {
2236
2236
 
2237
2237
  // Extract user prompts (skip <command-name> tool messages)
2238
2238
  const prompts = [];
2239
+ // Track last tool per file (Write wins over Edit)
2240
+ const fileToolMap = new Map(); // filePath → 'Write'|'Edit'
2239
2241
  for (const m of messages) {
2240
- if (m.type !== 'user') continue;
2241
- const c = m.message?.content;
2242
- let text = '';
2243
- if (typeof c === 'string') text = c;
2244
- else if (Array.isArray(c)) {
2245
- text = c.filter(b => b.type === 'text' && !b.text?.includes('<command-name>')).map(b => b.text).join('\n');
2242
+ if (m.type === 'user') {
2243
+ const c = m.message?.content;
2244
+ let text = '';
2245
+ if (typeof c === 'string') text = c;
2246
+ else if (Array.isArray(c)) {
2247
+ text = c.filter(b => b.type === 'text' && !b.text?.includes('<command-name>')).map(b => b.text).join('\n');
2248
+ }
2249
+ text = text.trim();
2250
+ if (text && text.length > 2) prompts.push(text);
2251
+ } else if (m.type === 'assistant') {
2252
+ const content = m.message?.content;
2253
+ if (!Array.isArray(content)) continue;
2254
+ for (const block of content) {
2255
+ if (block.type !== 'tool_use') continue;
2256
+ if ((block.name === 'Edit' || block.name === 'Write') && block.input?.file_path) {
2257
+ fileToolMap.set(block.input.file_path, block.name);
2258
+ }
2259
+ }
2246
2260
  }
2247
- text = text.trim();
2248
- if (text && text.length > 2) prompts.push(text);
2249
2261
  }
2250
2262
 
2251
2263
  const firstPrompt = prompts[0] || sessionId;
@@ -2256,7 +2268,12 @@ app.post('/api/sessions/:project/:sessionId/snapshot', async (req, res) => {
2256
2268
 
2257
2269
  const promptList = prompts.map((p, i) => `${i + 1}. ${p.replace(/\n+/g, ' ').slice(0, 200)}${p.length > 200 ? '…' : ''}`).join('\n');
2258
2270
 
2259
- const content = `${meta}\n\n## Prompts\n\n${promptList}\n\n## Notes\n\n`;
2271
+ const fileLines = [...fileToolMap.entries()]
2272
+ .map(([fp, tool]) => `- \`${fp}\`${tool === 'Write' ? ' *(created)*' : ''}`)
2273
+ .join('\n');
2274
+ const filesSection = fileToolMap.size > 0 ? `\n\n## Files changed\n\n${fileLines}` : '';
2275
+
2276
+ const content = `${meta}\n\n## Prompts\n\n${promptList}${filesSection}\n\n## Notes\n\n`;
2260
2277
 
2261
2278
  ensureNotesDir();
2262
2279
  const slug = firstPrompt.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 40) || 'snapshot';