jupyterlab_claude_code_extension 1.2.12 → 1.2.17

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
@@ -149,6 +149,7 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
149
149
  private _commands;
150
150
  private _contextMenu;
151
151
  private _branchSubmenu;
152
+ private _branchSessionMenu;
152
153
  private _lastBranches;
153
154
  private _lastBranchesCurrent;
154
155
  private _newSessionMenu;
package/lib/widget.js CHANGED
@@ -845,12 +845,14 @@ export class ClaudeCodeSessionsWidget extends Widget {
845
845
  starFilledIcon.element({ container: star });
846
846
  row.appendChild(star);
847
847
  }
848
- if (session.file_mtime) {
849
- const time = document.createElement('span');
850
- time.className = 'jp-ClaudeSessionsPanel-rowTime';
851
- time.textContent = this._formatRelativeTime(session.file_mtime);
852
- row.appendChild(time);
853
- }
848
+ // Always present (empty without an mtime) so the star column keeps
849
+ // the same anchor across every row in the panel.
850
+ const time = document.createElement('span');
851
+ time.className = 'jp-ClaudeSessionsPanel-rowTime';
852
+ time.textContent = session.file_mtime
853
+ ? this._formatRelativeTime(session.file_mtime)
854
+ : '';
855
+ row.appendChild(time);
854
856
  row.addEventListener('click', () => {
855
857
  if (removing) {
856
858
  return;
@@ -1073,12 +1075,11 @@ export class ClaudeCodeSessionsWidget extends Widget {
1073
1075
  }
1074
1076
  });
1075
1077
  this._commands.addCommand('claude-code-sessions:branch-session', {
1076
- label: 'Branch Session...',
1077
- icon: branchIcon,
1078
+ label: 'Normal',
1078
1079
  execute: () => void this._branchSession(false)
1079
1080
  });
1080
1081
  this._commands.addCommand('claude-code-sessions:branch-session-dangerous', {
1081
- label: 'Branch Session (Skip Permissions)...',
1082
+ label: 'Skip Permissions',
1082
1083
  icon: shieldIcon,
1083
1084
  execute: () => void this._branchSession(true)
1084
1085
  });
@@ -1116,6 +1117,17 @@ export class ClaudeCodeSessionsWidget extends Widget {
1116
1117
  this._branchSubmenu = new Menu({ commands: this._commands });
1117
1118
  this._branchSubmenu.addClass('jp-ClaudeSessionsContextMenu');
1118
1119
  this._branchSubmenu.title.label = 'Switch and Manage Sessions';
1120
+ // Submenu grouping the two branch-session launch modes.
1121
+ this._branchSessionMenu = new Menu({ commands: this._commands });
1122
+ this._branchSessionMenu.addClass('jp-ClaudeSessionsContextMenu');
1123
+ this._branchSessionMenu.title.label = 'Branch Session';
1124
+ this._branchSessionMenu.title.icon = branchIcon;
1125
+ this._branchSessionMenu.addItem({
1126
+ command: 'claude-code-sessions:branch-session'
1127
+ });
1128
+ this._branchSessionMenu.addItem({
1129
+ command: 'claude-code-sessions:branch-session-dangerous'
1130
+ });
1119
1131
  this._contextMenu = new Menu({ commands: this._commands });
1120
1132
  this._contextMenu.addClass('jp-ClaudeSessionsContextMenu');
1121
1133
  this._rebuildContextMenu(false);
@@ -1154,10 +1166,8 @@ export class ClaudeCodeSessionsWidget extends Widget {
1154
1166
  });
1155
1167
  }
1156
1168
  this._contextMenu.addItem({
1157
- command: 'claude-code-sessions:branch-session'
1158
- });
1159
- this._contextMenu.addItem({
1160
- command: 'claude-code-sessions:branch-session-dangerous'
1169
+ type: 'submenu',
1170
+ submenu: this._branchSessionMenu
1161
1171
  });
1162
1172
  this._contextMenu.addItem({
1163
1173
  command: 'claude-code-sessions:cleanup-parallel'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyterlab_claude_code_extension",
3
- "version": "1.2.12",
3
+ "version": "1.2.17",
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",
@@ -318,12 +318,22 @@ describe('launch spinner dismiss contract', () => {
318
318
  const rowTime = (css.match(
319
319
  /\.jp-ClaudeSessionsPanel-rowTime \{[\s\S]*?\}/
320
320
  ) ?? [''])[0];
321
- expect(rowTime).toMatch(/width: 52px/);
321
+ expect(rowTime).toMatch(/width: 4em/);
322
+ expect(rowTime).toMatch(/white-space: nowrap/);
322
323
  expect(rowTime).toMatch(/text-align: right/);
323
324
  const branchTime = (css.match(
324
325
  /\.jp-ClaudeSessionsPanel-branchTime \{[\s\S]*?\}/
325
326
  ) ?? [''])[0];
326
- expect(branchTime).toMatch(/width: 52px/);
327
+ expect(branchTime).toMatch(/width: 4em/);
328
+ expect(branchTime).toMatch(/white-space: nowrap/);
329
+ // Stars line up vertically across the entire panel: every row keeps
330
+ // the time slot (empty without an mtime) and every section reserves
331
+ // the scrollbar gutter.
332
+ expect(widgetSrc).toMatch(/time\.textContent = session\.file_mtime\s*\?/);
333
+ const list = (css.match(/\.jp-ClaudeSessionsPanel-list \{[\s\S]*?\}/) ?? [
334
+ ''
335
+ ])[0];
336
+ expect(list).toMatch(/scrollbar-gutter: stable/);
327
337
  expect(branchTime).toMatch(/text-align: right/);
328
338
  });
329
339
 
@@ -337,14 +347,20 @@ describe('launch spinner dismiss contract', () => {
337
347
  );
338
348
  });
339
349
 
340
- it('branch session commands exist in normal and skip-permissions modes', () => {
350
+ it('branch session is a submenu with normal and skip-permissions entries', () => {
341
351
  expect(widgetSrc).toMatch(/claude-code-sessions:branch-session'/);
342
352
  expect(widgetSrc).toMatch(
343
353
  /claude-code-sessions:branch-session-dangerous/
344
354
  );
345
355
  expect(widgetSrc).toMatch(
346
- /Branch Session \(Skip Permissions\)\.\.\.[\s\S]{0,80}?icon: shieldIcon/
356
+ /_branchSessionMenu\.title\.label = 'Branch Session'/
357
+ );
358
+ expect(widgetSrc).toMatch(
359
+ /label: 'Skip Permissions',\s*icon: shieldIcon/
347
360
  );
361
+ expect(widgetSrc).toMatch(/submenu: this\._branchSessionMenu/);
362
+ // No ellipsis on the branch-session labels.
363
+ expect(widgetSrc).not.toMatch(/Branch Session\.\.\./);
348
364
  });
349
365
 
350
366
  it('branch session asks for a name and launches a known fork id', () => {
package/src/widget.ts CHANGED
@@ -996,12 +996,14 @@ export class ClaudeCodeSessionsWidget extends Widget {
996
996
  row.appendChild(star);
997
997
  }
998
998
 
999
- if (session.file_mtime) {
1000
- const time = document.createElement('span');
1001
- time.className = 'jp-ClaudeSessionsPanel-rowTime';
1002
- time.textContent = this._formatRelativeTime(session.file_mtime);
1003
- row.appendChild(time);
1004
- }
999
+ // Always present (empty without an mtime) so the star column keeps
1000
+ // the same anchor across every row in the panel.
1001
+ const time = document.createElement('span');
1002
+ time.className = 'jp-ClaudeSessionsPanel-rowTime';
1003
+ time.textContent = session.file_mtime
1004
+ ? this._formatRelativeTime(session.file_mtime)
1005
+ : '';
1006
+ row.appendChild(time);
1005
1007
 
1006
1008
  row.addEventListener('click', () => {
1007
1009
  if (removing) {
@@ -1252,13 +1254,12 @@ export class ClaudeCodeSessionsWidget extends Widget {
1252
1254
  });
1253
1255
 
1254
1256
  this._commands.addCommand('claude-code-sessions:branch-session', {
1255
- label: 'Branch Session...',
1256
- icon: branchIcon,
1257
+ label: 'Normal',
1257
1258
  execute: () => void this._branchSession(false)
1258
1259
  });
1259
1260
 
1260
1261
  this._commands.addCommand('claude-code-sessions:branch-session-dangerous', {
1261
- label: 'Branch Session (Skip Permissions)...',
1262
+ label: 'Skip Permissions',
1262
1263
  icon: shieldIcon,
1263
1264
  execute: () => void this._branchSession(true)
1264
1265
  });
@@ -1302,6 +1303,18 @@ export class ClaudeCodeSessionsWidget extends Widget {
1302
1303
  this._branchSubmenu.addClass('jp-ClaudeSessionsContextMenu');
1303
1304
  this._branchSubmenu.title.label = 'Switch and Manage Sessions';
1304
1305
 
1306
+ // Submenu grouping the two branch-session launch modes.
1307
+ this._branchSessionMenu = new Menu({ commands: this._commands });
1308
+ this._branchSessionMenu.addClass('jp-ClaudeSessionsContextMenu');
1309
+ this._branchSessionMenu.title.label = 'Branch Session';
1310
+ this._branchSessionMenu.title.icon = branchIcon;
1311
+ this._branchSessionMenu.addItem({
1312
+ command: 'claude-code-sessions:branch-session'
1313
+ });
1314
+ this._branchSessionMenu.addItem({
1315
+ command: 'claude-code-sessions:branch-session-dangerous'
1316
+ });
1317
+
1305
1318
  this._contextMenu = new Menu({ commands: this._commands });
1306
1319
  this._contextMenu.addClass('jp-ClaudeSessionsContextMenu');
1307
1320
  this._rebuildContextMenu(false);
@@ -1342,10 +1355,8 @@ export class ClaudeCodeSessionsWidget extends Widget {
1342
1355
  });
1343
1356
  }
1344
1357
  this._contextMenu.addItem({
1345
- command: 'claude-code-sessions:branch-session'
1346
- });
1347
- this._contextMenu.addItem({
1348
- command: 'claude-code-sessions:branch-session-dangerous'
1358
+ type: 'submenu',
1359
+ submenu: this._branchSessionMenu
1349
1360
  });
1350
1361
  this._contextMenu.addItem({
1351
1362
  command: 'claude-code-sessions:cleanup-parallel'
@@ -1803,6 +1814,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
1803
1814
  private _commands!: CommandRegistry;
1804
1815
  private _contextMenu!: Menu;
1805
1816
  private _branchSubmenu!: Menu;
1817
+ private _branchSessionMenu!: Menu;
1806
1818
  private _lastBranches: IBranch[] = [];
1807
1819
  private _lastBranchesCurrent = '';
1808
1820
  private _newSessionMenu!: Menu;
package/style/base.css CHANGED
@@ -155,6 +155,10 @@
155
155
  flex: 1 1 auto;
156
156
  overflow-y: auto;
157
157
  min-height: 0;
158
+
159
+ /* Reserve the scrollbar gutter in every section so star/time columns
160
+ line up across the entire panel, scrollbar or not. */
161
+ scrollbar-gutter: stable;
158
162
  }
159
163
 
160
164
  .jp-ClaudeSessionsPanel-row {
@@ -382,7 +386,8 @@
382
386
 
383
387
  .jp-ClaudeSessionsPanel-branchTime {
384
388
  flex: none;
385
- width: 52px;
389
+ width: 4em;
390
+ white-space: nowrap;
386
391
  text-align: right;
387
392
  color: var(--jp-ui-font-color2);
388
393
  font-size: var(--jp-ui-font-size0);
@@ -458,7 +463,8 @@
458
463
  column so values line up across rows; the star column sits before it. */
459
464
  .jp-ClaudeSessionsPanel-rowTime {
460
465
  flex: 0 0 auto;
461
- width: 52px;
466
+ width: 4em;
467
+ white-space: nowrap;
462
468
  text-align: right;
463
469
  color: var(--jp-ui-font-color2);
464
470
  font-size: var(--jp-ui-font-size0);