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.
Files changed (2) hide show
  1. package/index.ts +95 -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,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
- const cursor = isSelected ? accent('▶') : ' ';
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 = isSelected ? accent(entry.listing.id) : text(entry.listing.id);
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 + " " + id (8) + " "
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 = isSelected ? accent(cwdTruncated) : muted(cwdTruncated);
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('↑↓ navigate space/+/− fold enter compact shift+enter resume esc close'),
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 === '-')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goosedump",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Coding agent context data browser plugin for pi",
5
5
  "keywords": [
6
6
  "goosedump",