claude-starter 1.3.0 → 1.3.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.
Files changed (3) hide show
  1. package/README.md +10 -4
  2. package/index.js +247 -39
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -75,7 +75,9 @@ claude-starter
75
75
  | 🔀 | **多种排序** | 时间 / 大小 / 消息数 / 项目 |
76
76
  | 📎 | **复制 ID** | `c` 一键复制到剪贴板 |
77
77
  | 🔒 | **权限模式** | `m` 设置权限模式,`d` 一键 danger 模式恢复 |
78
+ | ✏️ | **重命名会话** | `r` 直接重命名,支持中文输入 |
78
79
  | 🗑️ | **删除会话** | `x` 删除不需要的会话 |
80
+ | ⌨️ | **Vim 快捷键** | `j`/`k` 上下,`g`/`G` 跳顶/底 |
79
81
  | 🧠 | **智能 CLI** | 自动检测 `mai-claude` / `claude` |
80
82
  | 🔐 | **完全本地** | 不联网,不上传,不追踪 |
81
83
 
@@ -110,11 +112,12 @@ claude-starter --help # 显示帮助信息
110
112
 
111
113
  | 按键 | 功能 |
112
114
  |:---:|------|
113
- | `↑` `↓` | 上下导航 |
115
+ | `↑` `↓` / `j` `k` | 上下导航 |
114
116
  | `Enter` | 新建 / 恢复对话 |
115
117
  | `n` | 直接新建 |
116
118
  | `d` | Danger 模式恢复(bypassPermissions) |
117
119
  | `m` | 权限模式选择器 |
120
+ | `r` | 重命名会话 |
118
121
  | `/` | 搜索 |
119
122
  | `Backspace` | 删除搜索字符,删空自动退出 |
120
123
  | `Esc` | 清空搜索 |
@@ -122,7 +125,7 @@ claude-starter --help # 显示帮助信息
122
125
  | `s` | 切换排序(时间/大小/消息数/项目) |
123
126
  | `c` | 复制 Session ID |
124
127
  | `x` / `Delete` | 删除会话 |
125
- | `Home` / `End` | 跳到顶 / 底 |
128
+ | `g` / `G` | 跳到顶 / 底 |
126
129
  | `Ctrl-D` / `Ctrl-U` | 翻页 |
127
130
  | `q` / `Ctrl-C` | 退出 |
128
131
 
@@ -180,7 +183,9 @@ Searches across **everything** — project names, Git branches, conversation con
180
183
  | 🔀 | **Sort Modes** | Sort by time, size, messages, or project |
181
184
  | 📎 | **Copy ID** | Press `c` to copy session ID |
182
185
  | 🔒 | **Permission Modes** | Press `m` to configure, `d` for quick danger-mode resume |
186
+ | ✏️ | **Rename Sessions** | Press `r` to rename, supports CJK input |
183
187
  | 🗑️ | **Delete Sessions** | Press `x` to remove unwanted sessions |
188
+ | ⌨️ | **Vim Keybindings** | `j`/`k` navigate, `g`/`G` jump to top/bottom |
184
189
  | 🧠 | **Smart CLI** | Auto-detects `mai-claude` vs `claude` |
185
190
  | 🔐 | **100% Local** | No network, no telemetry, no data leaves your machine |
186
191
 
@@ -219,11 +224,12 @@ claude-starter --help # Show help
219
224
 
220
225
  | Key | Action |
221
226
  |:---:|--------|
222
- | `↑` `↓` | Navigate sessions |
227
+ | `↑` `↓` / `j` `k` | Navigate sessions |
223
228
  | `Enter` | Start new / resume selected session |
224
229
  | `n` | New session |
225
230
  | `d` | Resume with bypassPermissions (danger mode) |
226
231
  | `m` | Permission mode picker |
232
+ | `r` | Rename session |
227
233
  | `/` | Search |
228
234
  | `Backspace` | Edit search, auto-exit when empty |
229
235
  | `Esc` | Clear filter |
@@ -231,7 +237,7 @@ claude-starter --help # Show help
231
237
  | `s` | Cycle sort mode (time/size/messages/project) |
232
238
  | `c` | Copy session ID |
233
239
  | `x` / `Delete` | Delete session |
234
- | `Home` / `End` | Jump to first / last |
240
+ | `g` / `G` | Jump to top / bottom |
235
241
  | `Ctrl-D` / `Ctrl-U` | Page down / up |
236
242
  | `q` / `Ctrl-C` | Quit |
237
243
 
package/index.js CHANGED
@@ -206,16 +206,27 @@ function loadSessionQuick(filePath, projectName) {
206
206
  const headBuf = Buffer.alloc(Math.min(8192, stat.size));
207
207
  fs.readSync(fd, headBuf, 0, headBuf.length, 0);
208
208
 
209
- let tailBuf = Buffer.alloc(0);
209
+ // Read tail with progressive expansion: start at 32KB, grow up to 256KB
210
+ // until we find a JSON line with a top-level timestamp (to get accurate lastTs).
211
+ let tailStr = '';
210
212
  if (stat.size > 8192) {
211
- const tailSize = Math.min(4096, stat.size - 8192);
212
- tailBuf = Buffer.alloc(tailSize);
213
- fs.readSync(fd, tailBuf, 0, tailSize, stat.size - tailSize);
213
+ const tailSizes = [32768, 65536, 131072, 262144];
214
+ for (const ts of tailSizes) {
215
+ const tailSize = Math.min(ts, stat.size - 8192);
216
+ const tailBuf = Buffer.alloc(tailSize);
217
+ fs.readSync(fd, tailBuf, 0, tailSize, stat.size - tailSize);
218
+ tailStr = tailBuf.toString('utf-8');
219
+ // Check if any parseable JSON line has a top-level timestamp
220
+ const hasTopLevelTs = tailStr.split('\n').some(line => {
221
+ try { return !!JSON.parse(line).timestamp; } catch { return false; }
222
+ });
223
+ if (hasTopLevelTs) break;
224
+ if (tailSize >= stat.size - 8192) break; // already read entire file
225
+ }
214
226
  }
215
227
  fs.closeSync(fd);
216
228
 
217
229
  const headStr = headBuf.toString('utf-8');
218
- const tailStr = tailBuf.toString('utf-8');
219
230
 
220
231
  let firstTs = null, lastTs = null;
221
232
  let version = '', gitBranch = '', cwd = '', permissionMode = '';
@@ -382,7 +393,9 @@ function formatTimestamp(ts) {
382
393
  if (!ts) return 'unknown';
383
394
  const d = new Date(ts);
384
395
  const now = new Date();
385
- const diffDays = Math.floor((now.getTime() - d.getTime()) / 86400000);
396
+ const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
397
+ const targetStart = new Date(d.getFullYear(), d.getMonth(), d.getDate());
398
+ const diffDays = Math.round((todayStart.getTime() - targetStart.getTime()) / 86400000);
386
399
  const time = d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false });
387
400
  if (diffDays === 0) return `Today ${time}`;
388
401
  if (diffDays === 1) return `Yesterday ${time}`;
@@ -520,16 +533,17 @@ function createApp() {
520
533
 
521
534
  function updateFooter() {
522
535
  const keys = [
523
- '{#7aa2f7-fg}{bold}n{/} {#565f89-fg}New{/}',
524
- '{#7aa2f7-fg}{bold}↵{/} {#565f89-fg}Resume{/}',
525
- '{#7aa2f7-fg}{bold}m{/} {#565f89-fg}Mode{/}',
526
- '{#f7768e-fg}{bold}d{/} {#565f89-fg}Danger{/}',
527
- '{#7aa2f7-fg}{bold}/{/} {#565f89-fg}Search{/}',
528
- '{#7aa2f7-fg}{bold}p{/} {#565f89-fg}Project{/}',
529
- '{#7aa2f7-fg}{bold}s{/} {#565f89-fg}Sort{/}',
530
- '{#7aa2f7-fg}{bold}c{/} {#565f89-fg}Copy ID{/}',
531
- '{#f7768e-fg}{bold}x{/} {#565f89-fg}Delete{/}',
532
- '{#7aa2f7-fg}{bold}q{/} {#565f89-fg}Quit{/}',
536
+ '{#9ece6a-fg}{bold}n{/} {#9ece6a-fg}New{/}',
537
+ '{#7aa2f7-fg}{bold}↵{/} {#7aa2f7-fg}Resume{/}',
538
+ '{#bb9af7-fg}{bold}m{/} {#bb9af7-fg}Mode{/}',
539
+ '{#f7768e-fg}{bold}d{/} {#f7768e-fg}Danger{/}',
540
+ '{#e0af68-fg}{bold}/{/} {#e0af68-fg}Search{/}',
541
+ '{#7dcfff-fg}{bold}p{/} {#7dcfff-fg}Project{/}',
542
+ '{#73daca-fg}{bold}s{/} {#73daca-fg}Sort{/}',
543
+ '{#565f89-fg}{bold}c{/} {#565f89-fg}Copy ID{/}',
544
+ '{#ff9e64-fg}{bold}r{/} {#ff9e64-fg}Rename{/}',
545
+ '{#f7768e-fg}{bold}x{/} {#f7768e-fg}Delete{/}',
546
+ '{#565f89-fg}{bold}q{/} {#565f89-fg}Quit{/}',
533
547
  ];
534
548
  footer.setContent(`\n ${keys.join(' {#414868-fg}│{/} ')}`);
535
549
  }
@@ -829,17 +843,15 @@ function createApp() {
829
843
  }
830
844
 
831
845
  screen.key(['down'], () => {
832
- if (popupOpen) return;
833
- if (isSearchMode) { isSearchMode = false; updateHeader(); screen.render(); }
846
+ if (renameMode || popupOpen || isSearchMode) return;
834
847
  moveSelection(1);
835
848
  });
836
849
  screen.key(['up'], () => {
837
- if (popupOpen) return;
838
- if (isSearchMode) { isSearchMode = false; updateHeader(); screen.render(); }
850
+ if (renameMode || popupOpen || isSearchMode) return;
839
851
  moveSelection(-1);
840
852
  });
841
853
  screen.key(['home'], () => {
842
- if (popupOpen) return;
854
+ if (renameMode || popupOpen) return;
843
855
  if (isSearchMode) { isSearchMode = false; }
844
856
  selectedIndex = -1;
845
857
  suppressSelectEvent = true; listPanel.select(0); suppressSelectEvent = false;
@@ -847,7 +859,7 @@ function createApp() {
847
859
  renderDetail(); updateHeader(); screen.render();
848
860
  });
849
861
  screen.key(['end'], () => {
850
- if (popupOpen) return;
862
+ if (renameMode || popupOpen) return;
851
863
  if (isSearchMode) { isSearchMode = false; }
852
864
  selectedIndex = Math.max(0, filteredSessions.length - 1);
853
865
  suppressSelectEvent = true; listPanel.select(selectedIndex + 1); suppressSelectEvent = false;
@@ -855,31 +867,86 @@ function createApp() {
855
867
  renderDetail(); updateHeader(); screen.render();
856
868
  });
857
869
  screen.key(['pagedown', 'C-d'], () => {
858
- if (popupOpen) return;
870
+ if (renameMode || popupOpen) return;
859
871
  if (isSearchMode) { isSearchMode = false; updateHeader(); screen.render(); }
860
872
  moveSelection(Math.floor((listPanel.height || 20) / 2));
861
873
  });
862
874
  screen.key(['pageup', 'C-u'], () => {
863
- if (popupOpen) return;
875
+ if (renameMode || popupOpen) return;
864
876
  if (isSearchMode) { isSearchMode = false; updateHeader(); screen.render(); }
865
877
  moveSelection(-Math.floor((listPanel.height || 20) / 2));
866
878
  });
867
879
 
868
880
  // Search
869
881
  screen.key(['/'], () => {
870
- if (isSearchMode) return;
882
+ if (renameMode || isSearchMode) return;
871
883
  isSearchMode = true; filterText = ''; applyFilter();
872
884
  });
873
885
 
874
886
  screen.on('keypress', (ch, key) => {
875
- // Backspace: always works when there's filter text, regardless of search mode
876
- if (key.name === 'backspace' && filterText) {
877
- filterText = filterText.slice(0, -1);
878
- selectedIndex = -1;
879
- isSearchMode = !!filterText; // exit search when empty
880
- applyFilter();
887
+ // ── Rename mode: capture all input ──
888
+ if (renameMode) {
889
+ if (key.name === 'return' || key.name === 'enter') {
890
+ const session = renameSession;
891
+ const value = renameValue;
892
+ closeRename();
893
+ submitRename(session, value);
894
+ return;
895
+ }
896
+ if (key.name === 'escape') {
897
+ closeRename();
898
+ listPanel.focus();
899
+ screen.render();
900
+ return;
901
+ }
902
+ if (key.name === 'backspace') {
903
+ if (renameValue.length > 0) {
904
+ renameValue = [...renameValue].slice(0, -1).join('');
905
+ renderRenameInput();
906
+ }
907
+ return;
908
+ }
909
+ if (ch && ch.length >= 1 && ch.charCodeAt(0) >= 32 && !key.ctrl && !key.meta) {
910
+ renameValue += ch;
911
+ renderRenameInput();
912
+ }
913
+ return; // swallow all keys while in rename mode
914
+ }
915
+
916
+ // Backspace: delete search char, or exit search mode if empty
917
+ if (key.name === 'backspace') {
918
+ if (filterText) {
919
+ filterText = filterText.slice(0, -1);
920
+ selectedIndex = -1;
921
+ isSearchMode = !!filterText;
922
+ applyFilter();
923
+ } else if (isSearchMode) {
924
+ isSearchMode = false;
925
+ applyFilter();
926
+ }
881
927
  return;
882
928
  }
929
+
930
+ // Vim-like navigation (only when NOT in search mode)
931
+ if (!isSearchMode && !popupOpen) {
932
+ if (ch === 'j') { moveSelection(1); return; }
933
+ if (ch === 'k') { moveSelection(-1); return; }
934
+ if (ch === 'G') {
935
+ selectedIndex = Math.max(0, filteredSessions.length - 1);
936
+ suppressSelectEvent = true; listPanel.select(selectedIndex + 1); suppressSelectEvent = false;
937
+ listPanel.childBase = Math.max(0, selectedIndex + 1 - listPanel.height + 1);
938
+ renderDetail(); updateHeader(); screen.render();
939
+ return;
940
+ }
941
+ if (ch === 'g') {
942
+ selectedIndex = -1;
943
+ suppressSelectEvent = true; listPanel.select(0); suppressSelectEvent = false;
944
+ listPanel.childBase = 0;
945
+ renderDetail(); updateHeader(); screen.render();
946
+ return;
947
+ }
948
+ }
949
+
883
950
  if (!isSearchMode) return;
884
951
  if (key.name === 'return' || key.name === 'enter') { isSearchMode = false; renderAll(); return; }
885
952
  if (key.name === 'escape') { isSearchMode = false; filterText = ''; applyFilter(); return; }
@@ -937,7 +1004,23 @@ function createApp() {
937
1004
  child.on('exit', (code) => process.exit(code || 0));
938
1005
  }
939
1006
 
1007
+ // Track the rename confirm popup and its session for Enter handling
1008
+ let renameConfirmPopup = null;
1009
+ let renameConfirmSession = null;
1010
+
940
1011
  screen.key(['enter'], () => {
1012
+ if (renameMode) return;
1013
+ if (renameJustFinished) return;
1014
+ // Handle rename confirm popup Enter
1015
+ if (renameConfirmPopup && popupOpen) {
1016
+ const session = renameConfirmSession;
1017
+ renameConfirmPopup.destroy();
1018
+ renameConfirmPopup = null;
1019
+ renameConfirmSession = null;
1020
+ popupOpen = false;
1021
+ resumeSession(session);
1022
+ return;
1023
+ }
941
1024
  if (isSearchMode) { isSearchMode = false; renderAll(); return; }
942
1025
  if (popupOpen) return;
943
1026
  if (selectedIndex === -1) { startNewSession(); return; }
@@ -947,13 +1030,13 @@ function createApp() {
947
1030
 
948
1031
  // Quick shortcut: n = new session
949
1032
  screen.key(['n'], () => {
950
- if (isSearchMode) return;
1033
+ if (renameMode || isSearchMode) return;
951
1034
  startNewSession();
952
1035
  });
953
1036
 
954
1037
  // Copy session ID
955
1038
  screen.key(['c'], () => {
956
- if (isSearchMode) return;
1039
+ if (renameMode || isSearchMode) return;
957
1040
  if (filteredSessions.length === 0) return;
958
1041
  const sid = filteredSessions[selectedIndex].sessionId;
959
1042
  try {
@@ -1097,14 +1180,14 @@ function createApp() {
1097
1180
 
1098
1181
  // ─── Quick dangerous resume (d key) ────────────────────────────────────
1099
1182
  screen.key(['d'], () => {
1100
- if (isSearchMode || popupOpen) return;
1183
+ if (renameMode || isSearchMode || popupOpen) return;
1101
1184
  if (selectedIndex < 0 || selectedIndex >= filteredSessions.length) return;
1102
1185
  resumeSession(filteredSessions[selectedIndex], 'bypassPermissions');
1103
1186
  });
1104
1187
 
1105
1188
  // ─── Permission mode picker (m key) ───────────────────────────────────
1106
1189
  screen.key(['m'], () => {
1107
- if (isSearchMode || popupOpen) return;
1190
+ if (renameMode || isSearchMode || popupOpen) return;
1108
1191
  if (selectedIndex < 0 || selectedIndex >= filteredSessions.length) return;
1109
1192
  showPermissionModePicker(filteredSessions[selectedIndex]);
1110
1193
  });
@@ -1169,18 +1252,143 @@ function createApp() {
1169
1252
  }
1170
1253
 
1171
1254
  screen.key(['x', 'delete'], () => {
1172
- if (isSearchMode || popupOpen) return;
1255
+ if (renameMode || isSearchMode || popupOpen) return;
1173
1256
  if (selectedIndex < 0 || selectedIndex >= filteredSessions.length) return;
1174
1257
  showDeleteConfirm(filteredSessions[selectedIndex]);
1175
1258
  });
1176
1259
 
1177
- screen.key(['s'], () => { if (!isSearchMode) cycleSort(); });
1178
- screen.key(['p'], () => { if (!isSearchMode) showProjectPicker(); });
1260
+ // ─── Rename Session ───────────────────────────────────────────────────
1261
+ const stringWidth = require('string-width');
1262
+ let renameMode = false;
1263
+ let renameJustFinished = false;
1264
+ let renameValue = '';
1265
+ let renameSession = null;
1266
+ let renamePopup = null;
1267
+ let renameDisplay = null;
1268
+ const renameMaxWidth = 46;
1269
+
1270
+ function renderRenameInput() {
1271
+ let display = renameValue;
1272
+ while (stringWidth(display) > renameMaxWidth && display.length > 0) {
1273
+ display = display.substring(1);
1274
+ }
1275
+ renameDisplay.setContent(display + '▌');
1276
+ screen.render();
1277
+ }
1278
+
1279
+ function showRenameInput(session) {
1280
+ renameSession = session;
1281
+ renameValue = session.customTitle || '';
1282
+
1283
+ renamePopup = blessed.box({
1284
+ parent: screen, top: 'center', left: 'center',
1285
+ width: 52, height: 7,
1286
+ label: ' {bold}{#73daca-fg}Rename Session{/} ',
1287
+ tags: true, border: { type: 'line' },
1288
+ style: {
1289
+ border: { fg: '#73daca' }, bg: '#24283b', fg: '#a9b1d6',
1290
+ label: { fg: '#73daca' },
1291
+ },
1292
+ });
1293
+
1294
+ renameDisplay = blessed.box({
1295
+ parent: renamePopup,
1296
+ top: 1, left: 1, right: 1, height: 1,
1297
+ tags: false,
1298
+ style: { fg: 'white', bg: '#1a1b26' },
1299
+ });
1300
+
1301
+ blessed.box({
1302
+ parent: renamePopup,
1303
+ top: 3, left: 1, right: 1, height: 1,
1304
+ tags: true,
1305
+ style: { bg: '#24283b' },
1306
+ content: ' {#9ece6a-fg}{bold}Enter{/}{#a9b1d6-fg} Save {/}{#565f89-fg}Esc{/}{#a9b1d6-fg} Cancel{/}',
1307
+ });
1308
+
1309
+ popupOpen = true;
1310
+ renameMode = true;
1311
+ renderRenameInput();
1312
+ }
1313
+
1314
+ function closeRename() {
1315
+ renameMode = false;
1316
+ if (renamePopup) { renamePopup.destroy(); renamePopup = null; }
1317
+ popupOpen = false;
1318
+ renameSession = null;
1319
+ renameDisplay = null;
1320
+ }
1321
+
1322
+ function submitRename(session, newTitle) {
1323
+ newTitle = (newTitle || '').trim();
1324
+
1325
+ // Save to meta
1326
+ if (!meta.sessions[session.sessionId]) meta.sessions[session.sessionId] = {};
1327
+ meta.sessions[session.sessionId].customTitle = newTitle || undefined;
1328
+ if (!newTitle) delete meta.sessions[session.sessionId].customTitle;
1329
+ saveMeta(meta);
1330
+
1331
+ // Update in-memory session
1332
+ session.customTitle = newTitle;
1333
+
1334
+ // Also append to JSONL file so Claude Code sees it
1335
+ if (newTitle && fs.existsSync(session.filePath)) {
1336
+ try {
1337
+ const entry = JSON.stringify({ type: 'custom-title', customTitle: newTitle });
1338
+ fs.appendFileSync(session.filePath, '\n' + entry);
1339
+ } catch (e) { /* silently fail */ }
1340
+ }
1341
+
1342
+ renderAll();
1343
+
1344
+ // Ask whether to resume this session after rename
1345
+ // We use renameJustFinished flag to prevent the Enter key from rename
1346
+ // from immediately triggering resume
1347
+ renameJustFinished = true;
1348
+ setTimeout(() => { renameJustFinished = false; }, 200);
1349
+
1350
+ setTimeout(() => {
1351
+ const titleLabel = newTitle ? `{#73daca-fg}${esc(newTitle)}{/}` : '{#565f89-fg}(title cleared){/}';
1352
+ renameConfirmSession = session;
1353
+ renameConfirmPopup = blessed.box({
1354
+ parent: screen, top: 'center', left: 'center',
1355
+ width: 48, height: 8,
1356
+ label: ' {bold}{#9ece6a-fg}Renamed{/} ',
1357
+ tags: true, border: { type: 'line' },
1358
+ style: {
1359
+ border: { fg: '#9ece6a' }, bg: '#24283b', fg: '#a9b1d6',
1360
+ label: { fg: '#9ece6a' },
1361
+ },
1362
+ content: `\n ${titleLabel}\n\n {#9ece6a-fg}{bold}Enter{/}{#a9b1d6-fg} Resume {/}{#565f89-fg}Esc{/}{#a9b1d6-fg} Back to list{/}`,
1363
+ });
1364
+ popupOpen = true;
1365
+ renameConfirmPopup.focus();
1366
+ screen.render();
1367
+
1368
+ renameConfirmPopup.key(['escape', 'q'], () => {
1369
+ renameConfirmPopup.destroy();
1370
+ renameConfirmPopup = null;
1371
+ renameConfirmSession = null;
1372
+ popupOpen = false;
1373
+ renderAll();
1374
+ });
1375
+ }, 50);
1376
+ }
1377
+
1378
+ screen.key(['r'], () => {
1379
+ if (isSearchMode || popupOpen) return;
1380
+ if (selectedIndex < 0 || selectedIndex >= filteredSessions.length) return;
1381
+ showRenameInput(filteredSessions[selectedIndex]);
1382
+ });
1383
+
1384
+ screen.key(['s'], () => { if (!renameMode && !isSearchMode) cycleSort(); });
1385
+ screen.key(['p'], () => { if (!renameMode && !isSearchMode) showProjectPicker(); });
1179
1386
  screen.key(['escape'], () => {
1387
+ if (renameMode) return; // handled in keypress
1180
1388
  if (isSearchMode) { isSearchMode = false; filterText = ''; applyFilter(); return; }
1181
1389
  filterText = ''; selectedIndex = -1; applyFilter();
1182
1390
  });
1183
- screen.key(['q', 'C-c'], () => { process.stdout.write('\x1b[0m'); screen.destroy(); process.exit(0); });
1391
+ screen.key(['q', 'C-c'], () => { if (renameMode) return; process.stdout.write('\x1b[0m'); screen.destroy(); process.exit(0); });
1184
1392
 
1185
1393
  // Remove blessed's built-in wheel handlers (they call select which changes selection)
1186
1394
  listPanel.removeAllListeners('element wheeldown');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-starter",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "A beautiful terminal UI for managing Claude Code sessions — start new or resume past conversations",
5
5
  "main": "index.js",
6
6
  "bin": {