pi-goosedump 0.7.1 → 0.7.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.
- package/index.ts +96 -9
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -416,6 +416,13 @@ function goosedumpCompact(
|
|
|
416
416
|
return renderCompactSummary(json);
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
+
function goosedumpDelete(id: string, options: { dryRun?: boolean } = {}): string {
|
|
420
|
+
const args = ['delete'];
|
|
421
|
+
if (options.dryRun) args.push('--dry-run');
|
|
422
|
+
args.push(id);
|
|
423
|
+
return runGoosedump(args);
|
|
424
|
+
}
|
|
425
|
+
|
|
419
426
|
export interface GoosedumpIntegrationOptions {
|
|
420
427
|
registerTool?: boolean;
|
|
421
428
|
overrideDefaultCompaction?: boolean;
|
|
@@ -665,9 +672,9 @@ async function runSessionBrowser(
|
|
|
665
672
|
const OVERLAY_WIDTH = 72;
|
|
666
673
|
|
|
667
674
|
// Build tree from flat listings using parent relationships.
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
675
|
+
let listingIds = new Set(listings.map((l) => l.id));
|
|
676
|
+
let roots = listings.filter((l) => l.parent === null || !listingIds.has(l.parent));
|
|
677
|
+
let childrenMap = new Map<string, GoosedumpListing[]>();
|
|
671
678
|
for (const l of listings) {
|
|
672
679
|
if (l.parent !== null) {
|
|
673
680
|
const siblings = childrenMap.get(l.parent) ?? [];
|
|
@@ -676,6 +683,19 @@ async function runSessionBrowser(
|
|
|
676
683
|
}
|
|
677
684
|
}
|
|
678
685
|
|
|
686
|
+
function rebuildTree(): void {
|
|
687
|
+
listingIds = new Set(listings.map((l) => l.id));
|
|
688
|
+
roots = listings.filter((l) => l.parent === null || !listingIds.has(l.parent));
|
|
689
|
+
childrenMap = new Map<string, GoosedumpListing[]>();
|
|
690
|
+
for (const l of listings) {
|
|
691
|
+
if (l.parent !== null) {
|
|
692
|
+
const siblings = childrenMap.get(l.parent) ?? [];
|
|
693
|
+
siblings.push(l);
|
|
694
|
+
childrenMap.set(l.parent, siblings);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
679
699
|
function truncateCwd(cwd: string, maxLen: number): string {
|
|
680
700
|
if (cwd.length <= maxLen) return cwd;
|
|
681
701
|
const head = Math.floor(maxLen / 2) + 2;
|
|
@@ -710,6 +730,7 @@ async function runSessionBrowser(
|
|
|
710
730
|
let compactLines: string[] = [];
|
|
711
731
|
let compactScroll = 0;
|
|
712
732
|
let compactTitle = '';
|
|
733
|
+
let pendingDeletionId: string | null = null;
|
|
713
734
|
|
|
714
735
|
const COMPACT_VIEWPORT = 20;
|
|
715
736
|
const LIST_VIEWPORT = 20;
|
|
@@ -719,6 +740,27 @@ async function runSessionBrowser(
|
|
|
719
740
|
displayList = flattenTree(roots, expandedNodes, 0);
|
|
720
741
|
}
|
|
721
742
|
|
|
743
|
+
function executeDeletion(): void {
|
|
744
|
+
try {
|
|
745
|
+
const id = pendingDeletionId!;
|
|
746
|
+
goosedumpDelete(id);
|
|
747
|
+
// Remove from listings and rebuild tree
|
|
748
|
+
const idx = listings.findIndex((l) => l.id === id);
|
|
749
|
+
if (idx >= 0) listings.splice(idx, 1);
|
|
750
|
+
rebuildTree();
|
|
751
|
+
rebuildDisplayList();
|
|
752
|
+
if (selectedIndex >= displayList.length) {
|
|
753
|
+
selectedIndex = Math.max(0, displayList.length - 1);
|
|
754
|
+
}
|
|
755
|
+
pendingDeletionId = null;
|
|
756
|
+
} catch (err) {
|
|
757
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
758
|
+
ctx.ui.notify(`Failed to delete session: ${msg}`, 'error');
|
|
759
|
+
pendingDeletionId = null;
|
|
760
|
+
}
|
|
761
|
+
tui.requestRender();
|
|
762
|
+
}
|
|
763
|
+
|
|
722
764
|
return {
|
|
723
765
|
render(width: number): string[] {
|
|
724
766
|
const innerW = width - 4;
|
|
@@ -773,21 +815,30 @@ async function runSessionBrowser(
|
|
|
773
815
|
const absolute = listScroll + i;
|
|
774
816
|
const entry = window[i];
|
|
775
817
|
const isSelected = absolute === selectedIndex;
|
|
776
|
-
|
|
777
|
-
|
|
818
|
+
const deletePending =
|
|
819
|
+
pendingDeletionId !== null && entry.listing.id === pendingDeletionId;
|
|
820
|
+
const cursor = deletePending ? dim('␡ ') : isSelected ? accent('▶') : ' ';
|
|
778
821
|
const indent = ' '.repeat(entry.depth * 2);
|
|
779
822
|
const toggle = entry.hasChildren
|
|
780
823
|
? expandedNodes.has(entry.listing.id)
|
|
781
824
|
? muted('−')
|
|
782
825
|
: muted('+')
|
|
783
826
|
: ' ';
|
|
784
|
-
const idText =
|
|
827
|
+
const idText = deletePending
|
|
828
|
+
? dim(entry.listing.id)
|
|
829
|
+
: isSelected
|
|
830
|
+
? accent(entry.listing.id)
|
|
831
|
+
: text(entry.listing.id);
|
|
785
832
|
|
|
786
|
-
// Prefix: " ▶" (3) + indent + toggle + " "
|
|
833
|
+
// Prefix: " ▶" (3) or "␡ " (3) + indent + toggle + " " + id (8) + " "
|
|
787
834
|
const prefixLen = 3 + entry.depth * 2 + 1 + 1 + 8 + 1;
|
|
788
835
|
const cwdMax = Math.max(8, innerW - prefixLen);
|
|
789
836
|
const cwdTruncated = truncateCwd(entry.listing.cwd, cwdMax);
|
|
790
|
-
const cwdText =
|
|
837
|
+
const cwdText = deletePending
|
|
838
|
+
? muted(cwdTruncated)
|
|
839
|
+
: isSelected
|
|
840
|
+
? accent(cwdTruncated)
|
|
841
|
+
: muted(cwdTruncated);
|
|
791
842
|
|
|
792
843
|
const line = ` ${cursor}${indent}${toggle} ${idText} ${cwdText}`;
|
|
793
844
|
lines.push(makeRow(line, innerW, border));
|
|
@@ -798,11 +849,25 @@ async function runSessionBrowser(
|
|
|
798
849
|
lines.push(makeRow(dim(` (${position})`), innerW, border));
|
|
799
850
|
}
|
|
800
851
|
|
|
852
|
+
// Deletion confirmation
|
|
853
|
+
if (pendingDeletionId) {
|
|
854
|
+
lines.push(makeRow('', innerW, border));
|
|
855
|
+
lines.push(
|
|
856
|
+
makeRow(
|
|
857
|
+
dim(` Delete session ${pendingDeletionId}? enter=confirm esc=cancel`),
|
|
858
|
+
innerW,
|
|
859
|
+
border,
|
|
860
|
+
),
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
|
|
801
864
|
// Footer
|
|
802
865
|
lines.push(makeRow('', innerW, border));
|
|
803
866
|
lines.push(
|
|
804
867
|
makeRow(
|
|
805
|
-
dim(
|
|
868
|
+
dim(
|
|
869
|
+
'↑↓ navigate space/+/− fold enter compact shift+enter resume ctrl+d delete esc close',
|
|
870
|
+
),
|
|
806
871
|
innerW,
|
|
807
872
|
border,
|
|
808
873
|
),
|
|
@@ -866,6 +931,28 @@ async function runSessionBrowser(
|
|
|
866
931
|
return;
|
|
867
932
|
}
|
|
868
933
|
|
|
934
|
+
// Deletion confirmation: enter confirms, esc cancels
|
|
935
|
+
if (pendingDeletionId) {
|
|
936
|
+
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl('c'))) {
|
|
937
|
+
pendingDeletionId = null;
|
|
938
|
+
tui.requestRender();
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (matchesKey(data, Key.enter) || matchesKey(data, Key.return)) {
|
|
942
|
+
executeDeletion();
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Ctrl+D marks session for deletion
|
|
949
|
+
if (matchesKey(data, Key.ctrl('d'))) {
|
|
950
|
+
const listing = displayList[selectedIndex]?.listing;
|
|
951
|
+
if (listing) pendingDeletionId = listing.id;
|
|
952
|
+
tui.requestRender();
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
|
|
869
956
|
// Expand/collapse: space, +, or - key
|
|
870
957
|
const entry = displayList[selectedIndex];
|
|
871
958
|
if (entry && entry.hasChildren && (data === ' ' || data === '+' || data === '-')) {
|