jupyterlab_claude_code_extension 1.0.29 → 1.0.34

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/lib/index.js CHANGED
@@ -31,9 +31,10 @@ const plugin = {
31
31
  try {
32
32
  const settings = await settingRegistry.load(PLUGIN_ID);
33
33
  const apply = () => {
34
- const resolve = settings.get('resolveSessionNames')
35
- .composite;
36
- widget.setResolveSessionNames(resolve !== false);
34
+ const mode = settings.get('presentationMode').composite;
35
+ if (mode === 'session' || mode === 'folder' || mode === 'path') {
36
+ widget.setPresentationMode(mode);
37
+ }
37
38
  const limit = settings.get('recentLimit').composite;
38
39
  if (typeof limit === 'number') {
39
40
  widget.setRecentLimit(limit);
package/lib/widget.d.ts CHANGED
@@ -2,11 +2,12 @@ import { JupyterFrontEnd } from '@jupyterlab/application';
2
2
  import { ITerminalTracker } from '@jupyterlab/terminal';
3
3
  import { Widget } from '@lumino/widgets';
4
4
  import { Message } from '@lumino/messaging';
5
+ export type PresentationMode = 'session' | 'folder' | 'path';
5
6
  export declare class ClaudeCodeSessionsWidget extends Widget {
6
7
  constructor(app: JupyterFrontEnd, rootDir: string, terminalTracker?: ITerminalTracker | null);
7
8
  refresh(): void;
8
- /** Toggle whether explicit ``/rename`` names are honoured. */
9
- setResolveSessionNames(on: boolean): void;
9
+ /** Choose how rows are labelled: by session name, folder name, or path. */
10
+ setPresentationMode(mode: PresentationMode): void;
10
11
  /** Set how many rows the Recent section displays. */
11
12
  setRecentLimit(n: number): void;
12
13
  /** Toggle the --dangerously-skip-permissions flag on launched sessions. */
@@ -40,7 +41,8 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
40
41
  private _findTerminalForCwd;
41
42
  private _showCloseExistingDialog;
42
43
  private _wireTerminalDisposal;
43
- /** Apply the resolve-names setting + path-segment disambiguation. */
44
+ /** Apply the presentation-mode setting (path-segment disambiguation is
45
+ * handled separately in ``_disambiguate``). */
44
46
  private _displayName;
45
47
  private _basename;
46
48
  /** Walk path tails until every name in a colliding group is unique. */
@@ -74,7 +76,7 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
74
76
  private readonly _terminalsByPath;
75
77
  private readonly _pendingByPath;
76
78
  private readonly _rootDir;
77
- private _resolveNames;
79
+ private _presentationMode;
78
80
  private _recentLimit;
79
81
  private _dangerouslySkip;
80
82
  private _displayNames;
package/lib/widget.js CHANGED
@@ -6,6 +6,7 @@ import { claudeIcon, refreshIcon, removeIcon, shieldIcon, starFilledIcon } from
6
6
  const POLL_INTERVAL_MS = 10000;
7
7
  const DEFAULT_RECENT_LIMIT = 10;
8
8
  const EXPANDED_STORAGE_KEY = 'jupyterlab_claude_code_extension:expanded';
9
+ const DEFAULT_PRESENTATION_MODE = 'session';
9
10
  const SECTION_LABELS = {
10
11
  favourites: 'Favourites',
11
12
  recent: 'Recent',
@@ -65,7 +66,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
65
66
  this._removingPaths = new Set();
66
67
  this._terminalsByPath = new Map();
67
68
  this._pendingByPath = new Map();
68
- this._resolveNames = true;
69
+ this._presentationMode = DEFAULT_PRESENTATION_MODE;
69
70
  this._recentLimit = DEFAULT_RECENT_LIMIT;
70
71
  this._dangerouslySkip = false;
71
72
  this._displayNames = new Map();
@@ -88,12 +89,12 @@ export class ClaudeCodeSessionsWidget extends Widget {
88
89
  .catch(err => this._showError(err))
89
90
  .finally(() => this._setRefreshSpinning(false));
90
91
  }
91
- /** Toggle whether explicit ``/rename`` names are honoured. */
92
- setResolveSessionNames(on) {
93
- if (this._resolveNames === on) {
92
+ /** Choose how rows are labelled: by session name, folder name, or path. */
93
+ setPresentationMode(mode) {
94
+ if (this._presentationMode === mode) {
94
95
  return;
95
96
  }
96
- this._resolveNames = on;
97
+ this._presentationMode = mode;
97
98
  this._render();
98
99
  }
99
100
  /** Set how many rows the Recent section displays. */
@@ -417,12 +418,19 @@ export class ClaudeCodeSessionsWidget extends Widget {
417
418
  });
418
419
  }
419
420
  // -------------------------------------------------------------- rendering
420
- /** Apply the resolve-names setting + path-segment disambiguation. */
421
+ /** Apply the presentation-mode setting (path-segment disambiguation is
422
+ * handled separately in ``_disambiguate``). */
421
423
  _displayName(s) {
422
- if (!this._resolveNames) {
423
- return this._basename(s.project_path) || s.encoded_path;
424
+ const folder = this._basename(s.project_path) || s.encoded_path;
425
+ switch (this._presentationMode) {
426
+ case 'folder':
427
+ return folder;
428
+ case 'path':
429
+ return this._displayPath(s.project_path) || folder;
430
+ case 'session':
431
+ default:
432
+ return s.name || folder;
424
433
  }
425
- return s.name || this._basename(s.project_path) || s.encoded_path;
426
434
  }
427
435
  _basename(p) {
428
436
  if (!p) {
@@ -546,14 +554,14 @@ export class ClaudeCodeSessionsWidget extends Widget {
546
554
  }
547
555
  else {
548
556
  for (const item of items) {
549
- list.appendChild(this._renderRow(item));
557
+ list.appendChild(this._renderRow(item, key));
550
558
  }
551
559
  }
552
560
  section.appendChild(list);
553
561
  }
554
562
  this._bodyEl.appendChild(section);
555
563
  }
556
- _renderRow(session) {
564
+ _renderRow(session, sectionKey) {
557
565
  const row = document.createElement('div');
558
566
  row.className = 'jp-ClaudeSessionsPanel-row';
559
567
  row.title = this._buildRowTooltip(session);
@@ -582,7 +590,9 @@ export class ClaudeCodeSessionsWidget extends Widget {
582
590
  name.className = 'jp-ClaudeSessionsPanel-name';
583
591
  name.textContent = this._lookupName(session);
584
592
  row.appendChild(name);
585
- if (session.favourite) {
593
+ // No star in the Favourites section - every row there is a favourite
594
+ // by definition; stars are an indicator only useful in Recent/All.
595
+ if (session.favourite && sectionKey !== 'favourites') {
586
596
  const star = document.createElement('span');
587
597
  star.className = 'jp-ClaudeSessionsPanel-favStar';
588
598
  star.title = 'Favourite';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyterlab_claude_code_extension",
3
- "version": "1.0.29",
3
+ "version": "1.0.34",
4
4
  "description": "Browse, resume, and manage your Claude Code CLI sessions from a JupyterLab side panel. One click reactivates the right terminal - no duplicate tabs, live remote-control indicator, and favourites for the projects you keep coming back to.",
5
5
  "keywords": [
6
6
  "jupyter",
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ import { ITerminalTracker } from '@jupyterlab/terminal';
9
9
 
10
10
  import { requestAPI } from './request';
11
11
  import { IStatusResponse } from './types';
12
- import { ClaudeCodeSessionsWidget } from './widget';
12
+ import { ClaudeCodeSessionsWidget, PresentationMode } from './widget';
13
13
 
14
14
  const PLUGIN_ID = 'jupyterlab_claude_code_extension:plugin';
15
15
  const WIDGET_ID = 'jupyterlab-claude-code-extension';
@@ -59,9 +59,10 @@ const plugin: JupyterFrontEndPlugin<void> = {
59
59
  try {
60
60
  const settings = await settingRegistry.load(PLUGIN_ID);
61
61
  const apply = (): void => {
62
- const resolve = settings.get('resolveSessionNames')
63
- .composite as boolean;
64
- widget.setResolveSessionNames(resolve !== false);
62
+ const mode = settings.get('presentationMode').composite as string;
63
+ if (mode === 'session' || mode === 'folder' || mode === 'path') {
64
+ widget.setPresentationMode(mode as PresentationMode);
65
+ }
65
66
  const limit = settings.get('recentLimit').composite as number;
66
67
  if (typeof limit === 'number') {
67
68
  widget.setRecentLimit(limit);
package/src/widget.ts CHANGED
@@ -28,6 +28,10 @@ const EXPANDED_STORAGE_KEY = 'jupyterlab_claude_code_extension:expanded';
28
28
 
29
29
  type SectionKey = 'favourites' | 'recent' | 'all';
30
30
 
31
+ export type PresentationMode = 'session' | 'folder' | 'path';
32
+
33
+ const DEFAULT_PRESENTATION_MODE: PresentationMode = 'session';
34
+
31
35
  const SECTION_LABELS: Record<SectionKey, string> = {
32
36
  favourites: 'Favourites',
33
37
  recent: 'Recent',
@@ -113,12 +117,12 @@ export class ClaudeCodeSessionsWidget extends Widget {
113
117
  .finally(() => this._setRefreshSpinning(false));
114
118
  }
115
119
 
116
- /** Toggle whether explicit ``/rename`` names are honoured. */
117
- setResolveSessionNames(on: boolean): void {
118
- if (this._resolveNames === on) {
120
+ /** Choose how rows are labelled: by session name, folder name, or path. */
121
+ setPresentationMode(mode: PresentationMode): void {
122
+ if (this._presentationMode === mode) {
119
123
  return;
120
124
  }
121
- this._resolveNames = on;
125
+ this._presentationMode = mode;
122
126
  this._render();
123
127
  }
124
128
 
@@ -501,12 +505,19 @@ export class ClaudeCodeSessionsWidget extends Widget {
501
505
 
502
506
  // -------------------------------------------------------------- rendering
503
507
 
504
- /** Apply the resolve-names setting + path-segment disambiguation. */
508
+ /** Apply the presentation-mode setting (path-segment disambiguation is
509
+ * handled separately in ``_disambiguate``). */
505
510
  private _displayName(s: ISession): string {
506
- if (!this._resolveNames) {
507
- return this._basename(s.project_path) || s.encoded_path;
511
+ const folder = this._basename(s.project_path) || s.encoded_path;
512
+ switch (this._presentationMode) {
513
+ case 'folder':
514
+ return folder;
515
+ case 'path':
516
+ return this._displayPath(s.project_path) || folder;
517
+ case 'session':
518
+ default:
519
+ return s.name || folder;
508
520
  }
509
- return s.name || this._basename(s.project_path) || s.encoded_path;
510
521
  }
511
522
 
512
523
  private _basename(p: string): string {
@@ -649,7 +660,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
649
660
  list.appendChild(empty);
650
661
  } else {
651
662
  for (const item of items) {
652
- list.appendChild(this._renderRow(item));
663
+ list.appendChild(this._renderRow(item, key));
653
664
  }
654
665
  }
655
666
  section.appendChild(list);
@@ -658,7 +669,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
658
669
  this._bodyEl.appendChild(section);
659
670
  }
660
671
 
661
- private _renderRow(session: ISession): HTMLDivElement {
672
+ private _renderRow(session: ISession, sectionKey: SectionKey): HTMLDivElement {
662
673
  const row = document.createElement('div');
663
674
  row.className = 'jp-ClaudeSessionsPanel-row';
664
675
  row.title = this._buildRowTooltip(session);
@@ -689,7 +700,9 @@ export class ClaudeCodeSessionsWidget extends Widget {
689
700
  name.textContent = this._lookupName(session);
690
701
  row.appendChild(name);
691
702
 
692
- if (session.favourite) {
703
+ // No star in the Favourites section - every row there is a favourite
704
+ // by definition; stars are an indicator only useful in Recent/All.
705
+ if (session.favourite && sectionKey !== 'favourites') {
693
706
  const star = document.createElement('span');
694
707
  star.className = 'jp-ClaudeSessionsPanel-favStar';
695
708
  star.title = 'Favourite';
@@ -904,7 +917,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
904
917
  private readonly _terminalsByPath: Map<string, any> = new Map();
905
918
  private readonly _pendingByPath: Map<string, Promise<void>> = new Map();
906
919
  private readonly _rootDir: string;
907
- private _resolveNames: boolean = true;
920
+ private _presentationMode: PresentationMode = DEFAULT_PRESENTATION_MODE;
908
921
  private _recentLimit: number = DEFAULT_RECENT_LIMIT;
909
922
  private _dangerouslySkip: boolean = false;
910
923
  private _displayNames: Map<string, string> = new Map();