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.
Files changed (2) hide show
  1. package/index.ts +96 -9
  2. 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
- const listingIds = new Set(listings.map((l) => l.id));
669
- const roots = listings.filter((l) => l.parent === null || !listingIds.has(l.parent));
670
- const childrenMap = new Map<string, GoosedumpListing[]>();
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
- const cursor = isSelected ? accent('▶') : ' ';
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 = isSelected ? accent(entry.listing.id) : text(entry.listing.id);
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 + " " + id (8) + " "
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 = isSelected ? accent(cwdTruncated) : muted(cwdTruncated);
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('↑↓ navigate space/+/− fold enter compact shift+enter resume esc close'),
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 === '-')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goosedump",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Coding agent context data browser plugin for pi",
5
5
  "keywords": [
6
6
  "goosedump",