claude-starter 1.3.1 → 1.3.3
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/index.js +37 -5
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -393,7 +393,9 @@ function formatTimestamp(ts) {
|
|
|
393
393
|
if (!ts) return 'unknown';
|
|
394
394
|
const d = new Date(ts);
|
|
395
395
|
const now = new Date();
|
|
396
|
-
const
|
|
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);
|
|
397
399
|
const time = d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false });
|
|
398
400
|
if (diffDays === 0) return `Today ${time}`;
|
|
399
401
|
if (diffDays === 1) return `Yesterday ${time}`;
|
|
@@ -445,6 +447,16 @@ function runListMode(limit) {
|
|
|
445
447
|
function createApp() {
|
|
446
448
|
const allSessions = loadAllSessions();
|
|
447
449
|
const meta = loadMeta();
|
|
450
|
+
|
|
451
|
+
// Apply meta customTitles — these take priority over JSONL titles
|
|
452
|
+
// so renames persist even after continuing a conversation
|
|
453
|
+
for (const session of allSessions) {
|
|
454
|
+
const sm = meta.sessions[session.sessionId];
|
|
455
|
+
if (sm && sm.customTitle) {
|
|
456
|
+
session.customTitle = sm.customTitle;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
448
460
|
let filteredSessions = [...allSessions];
|
|
449
461
|
let selectedIndex = -1; // -1 = "New Session", 0+ = session index
|
|
450
462
|
let filterText = '';
|
|
@@ -530,6 +542,16 @@ function createApp() {
|
|
|
530
542
|
});
|
|
531
543
|
|
|
532
544
|
function updateFooter() {
|
|
545
|
+
if (isSearchMode) {
|
|
546
|
+
const keys = [
|
|
547
|
+
'{#e0af68-fg}{bold}↵{/} {#e0af68-fg}Confirm{/}',
|
|
548
|
+
'{#7aa2f7-fg}{bold}↑↓{/} {#7aa2f7-fg}Navigate{/}',
|
|
549
|
+
'{#565f89-fg}{bold}⌫{/} {#565f89-fg}Delete char{/}',
|
|
550
|
+
'{#565f89-fg}{bold}Esc{/} {#565f89-fg}Clear{/}',
|
|
551
|
+
];
|
|
552
|
+
footer.setContent(`\n ${keys.join(' {#414868-fg}│{/} ')}`);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
533
555
|
const keys = [
|
|
534
556
|
'{#9ece6a-fg}{bold}n{/} {#9ece6a-fg}New{/}',
|
|
535
557
|
'{#7aa2f7-fg}{bold}↵{/} {#7aa2f7-fg}Resume{/}',
|
|
@@ -652,6 +674,10 @@ function createApp() {
|
|
|
652
674
|
const session = filteredSessions[selectedIndex];
|
|
653
675
|
loadSessionDetail(session);
|
|
654
676
|
|
|
677
|
+
// Meta customTitle takes priority over JSONL
|
|
678
|
+
const sm = meta.sessions[session.sessionId];
|
|
679
|
+
if (sm && sm.customTitle) session.customTitle = sm.customTitle;
|
|
680
|
+
|
|
655
681
|
const color = getProjectColor(session.project, projectColorMap);
|
|
656
682
|
let c = '';
|
|
657
683
|
const sep = ` {#414868-fg}${'─'.repeat(44)}{/}`;
|
|
@@ -841,11 +867,13 @@ function createApp() {
|
|
|
841
867
|
}
|
|
842
868
|
|
|
843
869
|
screen.key(['down'], () => {
|
|
844
|
-
if (renameMode || popupOpen
|
|
870
|
+
if (renameMode || popupOpen) return;
|
|
871
|
+
if (isSearchMode) { isSearchMode = false; updateHeader(); updateFooter(); screen.render(); }
|
|
845
872
|
moveSelection(1);
|
|
846
873
|
});
|
|
847
874
|
screen.key(['up'], () => {
|
|
848
|
-
if (renameMode || popupOpen
|
|
875
|
+
if (renameMode || popupOpen) return;
|
|
876
|
+
if (isSearchMode) { isSearchMode = false; updateHeader(); updateFooter(); screen.render(); }
|
|
849
877
|
moveSelection(-1);
|
|
850
878
|
});
|
|
851
879
|
screen.key(['home'], () => {
|
|
@@ -878,7 +906,9 @@ function createApp() {
|
|
|
878
906
|
// Search
|
|
879
907
|
screen.key(['/'], () => {
|
|
880
908
|
if (renameMode || isSearchMode) return;
|
|
881
|
-
isSearchMode = true;
|
|
909
|
+
isSearchMode = true;
|
|
910
|
+
if (!filterText) filterText = ''; // keep existing filterText if any
|
|
911
|
+
updateHeader(); updateFooter(); screen.render();
|
|
882
912
|
});
|
|
883
913
|
|
|
884
914
|
screen.on('keypress', (ch, key) => {
|
|
@@ -946,7 +976,7 @@ function createApp() {
|
|
|
946
976
|
}
|
|
947
977
|
|
|
948
978
|
if (!isSearchMode) return;
|
|
949
|
-
if (key.name === 'return' || key.name === 'enter') { isSearchMode = false; renderAll(); return; }
|
|
979
|
+
if (key.name === 'return' || key.name === 'enter') { isSearchMode = false; searchJustConfirmed = true; renderAll(); return; }
|
|
950
980
|
if (key.name === 'escape') { isSearchMode = false; filterText = ''; applyFilter(); return; }
|
|
951
981
|
// Only accept printable characters (exclude control chars like \r \n \t)
|
|
952
982
|
if (ch && ch.length === 1 && ch.charCodeAt(0) >= 32 && !key.ctrl && !key.meta) { filterText += ch; selectedIndex = -1; applyFilter(); }
|
|
@@ -1005,10 +1035,12 @@ function createApp() {
|
|
|
1005
1035
|
// Track the rename confirm popup and its session for Enter handling
|
|
1006
1036
|
let renameConfirmPopup = null;
|
|
1007
1037
|
let renameConfirmSession = null;
|
|
1038
|
+
let searchJustConfirmed = false;
|
|
1008
1039
|
|
|
1009
1040
|
screen.key(['enter'], () => {
|
|
1010
1041
|
if (renameMode) return;
|
|
1011
1042
|
if (renameJustFinished) return;
|
|
1043
|
+
if (searchJustConfirmed) { searchJustConfirmed = false; return; }
|
|
1012
1044
|
// Handle rename confirm popup Enter
|
|
1013
1045
|
if (renameConfirmPopup && popupOpen) {
|
|
1014
1046
|
const session = renameConfirmSession;
|