pi-goosedump 0.7.1 → 0.7.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.ts +95 -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,26 @@ 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
|
+
// Refresh listings — goosedump may have also deleted subagent sessions
|
|
748
|
+
listings.splice(0, listings.length, ...goosedumpList());
|
|
749
|
+
rebuildTree();
|
|
750
|
+
rebuildDisplayList();
|
|
751
|
+
if (selectedIndex >= displayList.length) {
|
|
752
|
+
selectedIndex = Math.max(0, displayList.length - 1);
|
|
753
|
+
}
|
|
754
|
+
pendingDeletionId = null;
|
|
755
|
+
} catch (err) {
|
|
756
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
757
|
+
ctx.ui.notify(`Failed to delete session: ${msg}`, 'error');
|
|
758
|
+
pendingDeletionId = null;
|
|
759
|
+
}
|
|
760
|
+
tui.requestRender();
|
|
761
|
+
}
|
|
762
|
+
|
|
722
763
|
return {
|
|
723
764
|
render(width: number): string[] {
|
|
724
765
|
const innerW = width - 4;
|
|
@@ -773,21 +814,30 @@ async function runSessionBrowser(
|
|
|
773
814
|
const absolute = listScroll + i;
|
|
774
815
|
const entry = window[i];
|
|
775
816
|
const isSelected = absolute === selectedIndex;
|
|
776
|
-
|
|
777
|
-
|
|
817
|
+
const deletePending =
|
|
818
|
+
pendingDeletionId !== null && entry.listing.id === pendingDeletionId;
|
|
819
|
+
const cursor = deletePending ? dim('␡ ') : isSelected ? accent('▶') : ' ';
|
|
778
820
|
const indent = ' '.repeat(entry.depth * 2);
|
|
779
821
|
const toggle = entry.hasChildren
|
|
780
822
|
? expandedNodes.has(entry.listing.id)
|
|
781
823
|
? muted('−')
|
|
782
824
|
: muted('+')
|
|
783
825
|
: ' ';
|
|
784
|
-
const idText =
|
|
826
|
+
const idText = deletePending
|
|
827
|
+
? dim(entry.listing.id)
|
|
828
|
+
: isSelected
|
|
829
|
+
? accent(entry.listing.id)
|
|
830
|
+
: text(entry.listing.id);
|
|
785
831
|
|
|
786
|
-
// Prefix: " ▶" (3) + indent + toggle + " "
|
|
832
|
+
// Prefix: " ▶" (3) or "␡ " (3) + indent + toggle + " " + id (8) + " "
|
|
787
833
|
const prefixLen = 3 + entry.depth * 2 + 1 + 1 + 8 + 1;
|
|
788
834
|
const cwdMax = Math.max(8, innerW - prefixLen);
|
|
789
835
|
const cwdTruncated = truncateCwd(entry.listing.cwd, cwdMax);
|
|
790
|
-
const cwdText =
|
|
836
|
+
const cwdText = deletePending
|
|
837
|
+
? muted(cwdTruncated)
|
|
838
|
+
: isSelected
|
|
839
|
+
? accent(cwdTruncated)
|
|
840
|
+
: muted(cwdTruncated);
|
|
791
841
|
|
|
792
842
|
const line = ` ${cursor}${indent}${toggle} ${idText} ${cwdText}`;
|
|
793
843
|
lines.push(makeRow(line, innerW, border));
|
|
@@ -798,11 +848,25 @@ async function runSessionBrowser(
|
|
|
798
848
|
lines.push(makeRow(dim(` (${position})`), innerW, border));
|
|
799
849
|
}
|
|
800
850
|
|
|
851
|
+
// Deletion confirmation
|
|
852
|
+
if (pendingDeletionId) {
|
|
853
|
+
lines.push(makeRow('', innerW, border));
|
|
854
|
+
lines.push(
|
|
855
|
+
makeRow(
|
|
856
|
+
dim(` Delete session ${pendingDeletionId}? enter=confirm esc=cancel`),
|
|
857
|
+
innerW,
|
|
858
|
+
border,
|
|
859
|
+
),
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
|
|
801
863
|
// Footer
|
|
802
864
|
lines.push(makeRow('', innerW, border));
|
|
803
865
|
lines.push(
|
|
804
866
|
makeRow(
|
|
805
|
-
dim(
|
|
867
|
+
dim(
|
|
868
|
+
'↑↓ navigate space/+/− fold enter compact shift+enter resume ctrl+d delete esc close',
|
|
869
|
+
),
|
|
806
870
|
innerW,
|
|
807
871
|
border,
|
|
808
872
|
),
|
|
@@ -866,6 +930,28 @@ async function runSessionBrowser(
|
|
|
866
930
|
return;
|
|
867
931
|
}
|
|
868
932
|
|
|
933
|
+
// Deletion confirmation: enter confirms, esc cancels
|
|
934
|
+
if (pendingDeletionId) {
|
|
935
|
+
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl('c'))) {
|
|
936
|
+
pendingDeletionId = null;
|
|
937
|
+
tui.requestRender();
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
if (matchesKey(data, Key.enter) || matchesKey(data, Key.return)) {
|
|
941
|
+
executeDeletion();
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// Ctrl+D marks session for deletion
|
|
948
|
+
if (matchesKey(data, Key.ctrl('d'))) {
|
|
949
|
+
const listing = displayList[selectedIndex]?.listing;
|
|
950
|
+
if (listing) pendingDeletionId = listing.id;
|
|
951
|
+
tui.requestRender();
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
|
|
869
955
|
// Expand/collapse: space, +, or - key
|
|
870
956
|
const entry = displayList[selectedIndex];
|
|
871
957
|
if (entry && entry.hasChildren && (data === ' ' || data === '+' || data === '-')) {
|