jupyterlab_claude_code_extension 1.1.20 → 1.1.23

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/README.md CHANGED
@@ -19,8 +19,9 @@ Browse, resume, and manage your Claude Code sessions from a JupyterLab side pane
19
19
  - **One-click resume** - click a row to jump back into that session in a terminal. If a terminal for the project is already open, it's reused instead of duplicated
20
20
  - **Favorites** - star projects you keep coming back to via the right-click menu
21
21
  - **Remove** - drop a project's Claude history from the panel via the right-click menu; the history folder is moved to the trash (it honours JupyterLab's "move files to trash" setting), not deleted permanently
22
- - **Search** - fuzzy filter at the top of the panel
23
- - **Presentation modes** - label rows by session name, folder name, or path relative to the JupyterLab root
22
+ - **Clean up parallel sessions** - when a project has accumulated extra sessions beyond the main one, a right-click menu item (showing the count in brackets) removes them all, keeping only the main session; removed files honour the same trash setting
23
+ - **Search** - fuzzy filter toggled by the funnel button next to refresh
24
+ - **Presentation modes** - label rows by session name (so a `/rename` shows through), folder name, or path relative to the JupyterLab root
24
25
  - **Hover tooltip** with project path, last activity, message count, branch, and session id
25
26
  - **Auto-disabled** when the Claude Code CLI is not installed
26
27
 
package/lib/types.d.ts CHANGED
@@ -3,7 +3,7 @@ export interface ISession {
3
3
  encoded_path: string;
4
4
  session_id: string;
5
5
  name: string;
6
- name_source: 'rename' | 'basename';
6
+ name_source: 'session' | 'basename';
7
7
  summary: string;
8
8
  first_prompt: string;
9
9
  message_count: number;
@@ -13,6 +13,7 @@ export interface ISession {
13
13
  git_branch: string | null;
14
14
  remote_control: boolean;
15
15
  favourite: boolean;
16
+ extra_sessions: number;
16
17
  }
17
18
  export interface ISessionsListResponse {
18
19
  sessions: ISession[];
@@ -35,6 +36,12 @@ export interface IRemoveRequest {
35
36
  export interface IRemoveResponse {
36
37
  removed: string;
37
38
  }
39
+ export interface ICleanupRequest {
40
+ encoded_path: string;
41
+ }
42
+ export interface ICleanupResponse {
43
+ removed_count: number;
44
+ }
38
45
  export interface ILaunchTerminalRequest {
39
46
  project_path: string;
40
47
  session_id: string;
package/lib/widget.d.ts CHANGED
@@ -41,6 +41,7 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
41
41
  private _fetch;
42
42
  private _toggleFavourite;
43
43
  private _remove;
44
+ private _cleanupParallel;
44
45
  private _resumeInTerminal;
45
46
  private _doResumeInTerminal;
46
47
  /**
package/lib/widget.js CHANGED
@@ -334,6 +334,19 @@ export class ClaudeCodeSessionsWidget extends Widget {
334
334
  this._render();
335
335
  }
336
336
  }
337
+ async _cleanupParallel(session) {
338
+ try {
339
+ await requestAPI('sessions/cleanup', this._serverSettings, {
340
+ method: 'POST',
341
+ body: JSON.stringify({ encoded_path: session.encoded_path })
342
+ });
343
+ // Refresh so the row's extra_sessions count (and menu label) update
344
+ await this._fetch();
345
+ }
346
+ catch (err) {
347
+ this._showError(err);
348
+ }
349
+ }
337
350
  // -------------------------------------------------------------- terminal
338
351
  async _resumeInTerminal(session, forceDangerous = false) {
339
352
  // Coalesce concurrent clicks on the same row - subsequent clicks attach
@@ -527,6 +540,11 @@ export class ClaudeCodeSessionsWidget extends Widget {
527
540
  if (this._presentationMode === 'path') {
528
541
  return this._displayPath(s.project_path) || folder;
529
542
  }
543
+ // Honour the session name Claude records (e.g. a `/rename`); fall back
544
+ // to the folder basename when the backend reports no session name.
545
+ if (s.name_source === 'session' && s.name) {
546
+ return s.name;
547
+ }
530
548
  return folder;
531
549
  }
532
550
  _basename(p) {
@@ -892,6 +910,15 @@ export class ClaudeCodeSessionsWidget extends Widget {
892
910
  Clipboard.copyToSystem(path);
893
911
  }
894
912
  });
913
+ this._commands.addCommand('claude-code-sessions:cleanup-parallel', {
914
+ label: () => { var _a, _b; return `Clean Up Parallel Sessions (${(_b = (_a = this._activeSession) === null || _a === void 0 ? void 0 : _a.extra_sessions) !== null && _b !== void 0 ? _b : 0})`; },
915
+ isVisible: () => { var _a, _b; return ((_b = (_a = this._activeSession) === null || _a === void 0 ? void 0 : _a.extra_sessions) !== null && _b !== void 0 ? _b : 0) > 0; },
916
+ execute: () => {
917
+ if (this._activeSession) {
918
+ void this._cleanupParallel(this._activeSession);
919
+ }
920
+ }
921
+ });
895
922
  this._commands.addCommand('claude-code-sessions:remove', {
896
923
  label: 'Remove from Claude',
897
924
  icon: removeIcon,
@@ -918,6 +945,9 @@ export class ClaudeCodeSessionsWidget extends Widget {
918
945
  });
919
946
  this._contextMenu.addItem({ command: 'claude-code-sessions:copy-path' });
920
947
  this._contextMenu.addItem({ type: 'separator' });
948
+ this._contextMenu.addItem({
949
+ command: 'claude-code-sessions:cleanup-parallel'
950
+ });
921
951
  this._contextMenu.addItem({ command: 'claude-code-sessions:remove' });
922
952
  this._contextMenu.aboutToClose.connect(() => {
923
953
  // Only clear the visual highlight - DO NOT null _activeSession.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyterlab_claude_code_extension",
3
- "version": "1.1.20",
3
+ "version": "1.1.23",
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",
@@ -22,6 +22,7 @@ const session = (over: Partial<ISession> = {}): ISession => ({
22
22
  git_branch: null,
23
23
  remote_control: false,
24
24
  favourite: false,
25
+ extra_sessions: 0,
25
26
  ...over
26
27
  });
27
28
 
package/src/types.ts CHANGED
@@ -3,7 +3,7 @@ export interface ISession {
3
3
  encoded_path: string;
4
4
  session_id: string;
5
5
  name: string;
6
- name_source: 'rename' | 'basename';
6
+ name_source: 'session' | 'basename';
7
7
  summary: string;
8
8
  first_prompt: string;
9
9
  message_count: number;
@@ -13,6 +13,7 @@ export interface ISession {
13
13
  git_branch: string | null;
14
14
  remote_control: boolean;
15
15
  favourite: boolean;
16
+ extra_sessions: number;
16
17
  }
17
18
 
18
19
  export interface ISessionsListResponse {
@@ -42,6 +43,14 @@ export interface IRemoveResponse {
42
43
  removed: string;
43
44
  }
44
45
 
46
+ export interface ICleanupRequest {
47
+ encoded_path: string;
48
+ }
49
+
50
+ export interface ICleanupResponse {
51
+ removed_count: number;
52
+ }
53
+
45
54
  export interface ILaunchTerminalRequest {
46
55
  project_path: string;
47
56
  session_id: string;
package/src/widget.ts CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  import {
25
25
  IFavouriteResponse,
26
26
  ILaunchTerminalResponse,
27
+ ICleanupResponse,
27
28
  IRemoveResponse,
28
29
  ISession,
29
30
  ISessionsListResponse
@@ -406,6 +407,23 @@ export class ClaudeCodeSessionsWidget extends Widget {
406
407
  }
407
408
  }
408
409
 
410
+ private async _cleanupParallel(session: ISession): Promise<void> {
411
+ try {
412
+ await requestAPI<ICleanupResponse>(
413
+ 'sessions/cleanup',
414
+ this._serverSettings,
415
+ {
416
+ method: 'POST',
417
+ body: JSON.stringify({ encoded_path: session.encoded_path })
418
+ }
419
+ );
420
+ // Refresh so the row's extra_sessions count (and menu label) update
421
+ await this._fetch();
422
+ } catch (err) {
423
+ this._showError(err);
424
+ }
425
+ }
426
+
409
427
  // -------------------------------------------------------------- terminal
410
428
 
411
429
  private async _resumeInTerminal(
@@ -622,6 +640,11 @@ export class ClaudeCodeSessionsWidget extends Widget {
622
640
  if (this._presentationMode === 'path') {
623
641
  return this._displayPath(s.project_path) || folder;
624
642
  }
643
+ // Honour the session name Claude records (e.g. a `/rename`); fall back
644
+ // to the folder basename when the backend reports no session name.
645
+ if (s.name_source === 'session' && s.name) {
646
+ return s.name;
647
+ }
625
648
  return folder;
626
649
  }
627
650
 
@@ -1034,6 +1057,17 @@ export class ClaudeCodeSessionsWidget extends Widget {
1034
1057
  }
1035
1058
  });
1036
1059
 
1060
+ this._commands.addCommand('claude-code-sessions:cleanup-parallel', {
1061
+ label: () =>
1062
+ `Clean Up Parallel Sessions (${this._activeSession?.extra_sessions ?? 0})`,
1063
+ isVisible: () => (this._activeSession?.extra_sessions ?? 0) > 0,
1064
+ execute: () => {
1065
+ if (this._activeSession) {
1066
+ void this._cleanupParallel(this._activeSession);
1067
+ }
1068
+ }
1069
+ });
1070
+
1037
1071
  this._commands.addCommand('claude-code-sessions:remove', {
1038
1072
  label: 'Remove from Claude',
1039
1073
  icon: removeIcon,
@@ -1061,6 +1095,9 @@ export class ClaudeCodeSessionsWidget extends Widget {
1061
1095
  });
1062
1096
  this._contextMenu.addItem({ command: 'claude-code-sessions:copy-path' });
1063
1097
  this._contextMenu.addItem({ type: 'separator' });
1098
+ this._contextMenu.addItem({
1099
+ command: 'claude-code-sessions:cleanup-parallel'
1100
+ });
1064
1101
  this._contextMenu.addItem({ command: 'claude-code-sessions:remove' });
1065
1102
 
1066
1103
  this._contextMenu.aboutToClose.connect(() => {