jupyterlab_claude_code_extension 1.0.59 → 1.1.1

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/widget.d.ts CHANGED
@@ -73,6 +73,10 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
73
73
  private _lookupName;
74
74
  private _buildRowTooltip;
75
75
  private _displayPath;
76
+ /** Path relative to the JupyterLab server root (``''`` for the root
77
+ * itself), or ``null`` when the folder lies outside the root - in which
78
+ * case the file browser has no way to address it. */
79
+ private _pathUnderRoot;
76
80
  private _formatRelativeTime;
77
81
  private _setRefreshSpinning;
78
82
  private _setActiveRow;
package/lib/widget.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Clipboard, Dialog, Notification, showDialog } from '@jupyterlab/apputils';
2
- import { terminalIcon } from '@jupyterlab/ui-components';
2
+ import { folderIcon, terminalIcon } from '@jupyterlab/ui-components';
3
3
  import { CommandRegistry } from '@lumino/commands';
4
4
  import { Menu, Widget } from '@lumino/widgets';
5
5
  import { requestAPI } from './request';
@@ -746,6 +746,21 @@ export class ClaudeCodeSessionsWidget extends Widget {
746
746
  }
747
747
  return absolute;
748
748
  }
749
+ /** Path relative to the JupyterLab server root (``''`` for the root
750
+ * itself), or ``null`` when the folder lies outside the root - in which
751
+ * case the file browser has no way to address it. */
752
+ _pathUnderRoot(absolute) {
753
+ if (!this._rootDir) {
754
+ return null;
755
+ }
756
+ if (absolute === this._rootDir) {
757
+ return '';
758
+ }
759
+ if (absolute.startsWith(this._rootDir + '/')) {
760
+ return absolute.slice(this._rootDir.length + 1);
761
+ }
762
+ return null;
763
+ }
749
764
  _formatRelativeTime(epochMs) {
750
765
  if (!epochMs) {
751
766
  return 'unknown';
@@ -797,7 +812,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
797
812
  }
798
813
  });
799
814
  this._commands.addCommand('claude-code-sessions:resume', {
800
- label: 'Resume in Terminal',
815
+ label: 'Resume',
801
816
  execute: () => {
802
817
  if (this._activeSession) {
803
818
  void this._resumeInTerminal(this._activeSession);
@@ -828,6 +843,27 @@ export class ClaudeCodeSessionsWidget extends Widget {
828
843
  });
829
844
  }
830
845
  });
846
+ this._commands.addCommand('claude-code-sessions:show-in-filebrowser', {
847
+ label: 'Show in File Browser',
848
+ icon: folderIcon,
849
+ execute: () => {
850
+ if (!this._activeSession) {
851
+ return;
852
+ }
853
+ const rel = this._pathUnderRoot(this._activeSession.project_path);
854
+ if (rel === null) {
855
+ // The file browser can only navigate within the JupyterLab server
856
+ // root; a project folder outside it has no addressable path there.
857
+ Notification.warning('Folder is outside the JupyterLab root - the file browser cannot show it.', { autoClose: 4000 });
858
+ return;
859
+ }
860
+ // JL's built-in command navigates the default file browser to the
861
+ // path and reveals the browser panel.
862
+ void this._app.commands.execute('filebrowser:go-to-path', {
863
+ path: rel
864
+ });
865
+ }
866
+ });
831
867
  this._commands.addCommand('claude-code-sessions:copy-path', {
832
868
  label: 'Copy Path',
833
869
  execute: () => {
@@ -857,6 +893,9 @@ export class ClaudeCodeSessionsWidget extends Widget {
857
893
  this._contextMenu.addItem({
858
894
  command: 'claude-code-sessions:open-terminal'
859
895
  });
896
+ this._contextMenu.addItem({
897
+ command: 'claude-code-sessions:show-in-filebrowser'
898
+ });
860
899
  this._contextMenu.addItem({
861
900
  command: 'claude-code-sessions:toggle-favourite'
862
901
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyterlab_claude_code_extension",
3
- "version": "1.0.59",
3
+ "version": "1.1.1",
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/widget.ts CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  } from '@jupyterlab/apputils';
8
8
  import { ServerConnection } from '@jupyterlab/services';
9
9
  import { ITerminalTracker } from '@jupyterlab/terminal';
10
- import { terminalIcon } from '@jupyterlab/ui-components';
10
+ import { folderIcon, terminalIcon } from '@jupyterlab/ui-components';
11
11
  import { CommandRegistry } from '@lumino/commands';
12
12
  import { Menu, Widget } from '@lumino/widgets';
13
13
  import { Message } from '@lumino/messaging';
@@ -880,6 +880,22 @@ export class ClaudeCodeSessionsWidget extends Widget {
880
880
  return absolute;
881
881
  }
882
882
 
883
+ /** Path relative to the JupyterLab server root (``''`` for the root
884
+ * itself), or ``null`` when the folder lies outside the root - in which
885
+ * case the file browser has no way to address it. */
886
+ private _pathUnderRoot(absolute: string): string | null {
887
+ if (!this._rootDir) {
888
+ return null;
889
+ }
890
+ if (absolute === this._rootDir) {
891
+ return '';
892
+ }
893
+ if (absolute.startsWith(this._rootDir + '/')) {
894
+ return absolute.slice(this._rootDir.length + 1);
895
+ }
896
+ return null;
897
+ }
898
+
883
899
  private _formatRelativeTime(epochMs: number): string {
884
900
  if (!epochMs) {
885
901
  return 'unknown';
@@ -935,7 +951,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
935
951
  });
936
952
 
937
953
  this._commands.addCommand('claude-code-sessions:resume', {
938
- label: 'Resume in Terminal',
954
+ label: 'Resume',
939
955
  execute: () => {
940
956
  if (this._activeSession) {
941
957
  void this._resumeInTerminal(this._activeSession);
@@ -969,6 +985,31 @@ export class ClaudeCodeSessionsWidget extends Widget {
969
985
  }
970
986
  });
971
987
 
988
+ this._commands.addCommand('claude-code-sessions:show-in-filebrowser', {
989
+ label: 'Show in File Browser',
990
+ icon: folderIcon,
991
+ execute: () => {
992
+ if (!this._activeSession) {
993
+ return;
994
+ }
995
+ const rel = this._pathUnderRoot(this._activeSession.project_path);
996
+ if (rel === null) {
997
+ // The file browser can only navigate within the JupyterLab server
998
+ // root; a project folder outside it has no addressable path there.
999
+ Notification.warning(
1000
+ 'Folder is outside the JupyterLab root - the file browser cannot show it.',
1001
+ { autoClose: 4000 }
1002
+ );
1003
+ return;
1004
+ }
1005
+ // JL's built-in command navigates the default file browser to the
1006
+ // path and reveals the browser panel.
1007
+ void this._app.commands.execute('filebrowser:go-to-path', {
1008
+ path: rel
1009
+ });
1010
+ }
1011
+ });
1012
+
972
1013
  this._commands.addCommand('claude-code-sessions:copy-path', {
973
1014
  label: 'Copy Path',
974
1015
  execute: () => {
@@ -1000,6 +1041,9 @@ export class ClaudeCodeSessionsWidget extends Widget {
1000
1041
  this._contextMenu.addItem({
1001
1042
  command: 'claude-code-sessions:open-terminal'
1002
1043
  });
1044
+ this._contextMenu.addItem({
1045
+ command: 'claude-code-sessions:show-in-filebrowser'
1046
+ });
1003
1047
  this._contextMenu.addItem({
1004
1048
  command: 'claude-code-sessions:toggle-favourite'
1005
1049
  });