jupyterlab_claude_code_extension 1.0.26 → 1.0.32
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/icons.js +1 -1
- package/lib/widget.d.ts +1 -0
- package/lib/widget.js +32 -9
- package/package.json +1 -1
- package/src/icons.ts +1 -1
- package/src/widget.ts +35 -9
package/lib/icons.js
CHANGED
|
@@ -42,7 +42,7 @@ export const removeIcon = new LabIcon({
|
|
|
42
42
|
name: 'jupyterlab_claude_code_extension:remove',
|
|
43
43
|
svgstr: removeSvgStr
|
|
44
44
|
});
|
|
45
|
-
const shieldSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="
|
|
45
|
+
const shieldSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="13" height="13">
|
|
46
46
|
<path class="jp-icon3" fill="#616161" d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 10.99h7c-.53 4.12-3.28 7.79-7 8.94V12H5V6.3l7-3.11v8.8z"/>
|
|
47
47
|
</svg>`;
|
|
48
48
|
export const shieldIcon = new LabIcon({
|
package/lib/widget.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare class ClaudeCodeSessionsWidget extends Widget {
|
|
|
38
38
|
private _resumeInTerminal;
|
|
39
39
|
private _doResumeInTerminal;
|
|
40
40
|
private _findTerminalForCwd;
|
|
41
|
+
private _showCloseExistingDialog;
|
|
41
42
|
private _wireTerminalDisposal;
|
|
42
43
|
/** Apply the resolve-names setting + path-segment disambiguation. */
|
|
43
44
|
private _displayName;
|
package/lib/widget.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Dialog, showDialog } from '@jupyterlab/apputils';
|
|
1
2
|
import { CommandRegistry } from '@lumino/commands';
|
|
2
3
|
import { Menu, Widget } from '@lumino/widgets';
|
|
3
4
|
import { requestAPI } from './request';
|
|
@@ -308,21 +309,32 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
308
309
|
}
|
|
309
310
|
async _doResumeInTerminal(session, forceDangerous) {
|
|
310
311
|
try {
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
//
|
|
312
|
+
// Always prefer reusing an open terminal for this project. The
|
|
313
|
+
// skip-permissions flag can only be applied to a fresh pty, never
|
|
314
|
+
// retroactively. So if the user wants dangerous mode but an open
|
|
315
|
+
// terminal already exists, show a modal asking them to close it
|
|
316
|
+
// first - we won't auto-close, won't silently reuse the wrong mode.
|
|
317
|
+
// 1. In-memory microcache.
|
|
314
318
|
const cached = this._terminalsByPath.get(session.project_path);
|
|
315
319
|
if (cached && !cached.isDisposed) {
|
|
320
|
+
if (forceDangerous) {
|
|
321
|
+
await this._showCloseExistingDialog();
|
|
322
|
+
this._app.shell.activateById(cached.id);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
316
325
|
this._app.shell.activateById(cached.id);
|
|
317
326
|
return;
|
|
318
327
|
}
|
|
319
|
-
// 2. Walk every live terminal widget JL knows about
|
|
320
|
-
// server for the cwd of EVERY process in its pty's tree. Match if
|
|
321
|
-
// any one of them equals project_path.
|
|
328
|
+
// 2. Walk every live terminal widget JL knows about.
|
|
322
329
|
const found = await this._findTerminalForCwd(session.project_path);
|
|
323
330
|
if (found) {
|
|
324
331
|
this._terminalsByPath.set(session.project_path, found);
|
|
325
332
|
this._wireTerminalDisposal(session.project_path, found);
|
|
333
|
+
if (forceDangerous) {
|
|
334
|
+
await this._showCloseExistingDialog();
|
|
335
|
+
this._app.shell.activateById(found.id);
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
326
338
|
this._app.shell.activateById(found.id);
|
|
327
339
|
return;
|
|
328
340
|
}
|
|
@@ -384,6 +396,15 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
384
396
|
}
|
|
385
397
|
return null;
|
|
386
398
|
}
|
|
399
|
+
async _showCloseExistingDialog() {
|
|
400
|
+
await showDialog({
|
|
401
|
+
title: 'Existing Claude session is running',
|
|
402
|
+
body: 'A terminal for this project is already open. To launch with ' +
|
|
403
|
+
'--dangerously-skip-permissions, close that terminal first then ' +
|
|
404
|
+
'click "Resume (Skip Permissions)" again.',
|
|
405
|
+
buttons: [Dialog.okButton({ label: 'OK' })]
|
|
406
|
+
});
|
|
407
|
+
}
|
|
387
408
|
_wireTerminalDisposal(projectPath, widget) {
|
|
388
409
|
var _a;
|
|
389
410
|
if (!((_a = widget === null || widget === void 0 ? void 0 : widget.disposed) === null || _a === void 0 ? void 0 : _a.connect)) {
|
|
@@ -525,14 +546,14 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
525
546
|
}
|
|
526
547
|
else {
|
|
527
548
|
for (const item of items) {
|
|
528
|
-
list.appendChild(this._renderRow(item));
|
|
549
|
+
list.appendChild(this._renderRow(item, key));
|
|
529
550
|
}
|
|
530
551
|
}
|
|
531
552
|
section.appendChild(list);
|
|
532
553
|
}
|
|
533
554
|
this._bodyEl.appendChild(section);
|
|
534
555
|
}
|
|
535
|
-
_renderRow(session) {
|
|
556
|
+
_renderRow(session, sectionKey) {
|
|
536
557
|
const row = document.createElement('div');
|
|
537
558
|
row.className = 'jp-ClaudeSessionsPanel-row';
|
|
538
559
|
row.title = this._buildRowTooltip(session);
|
|
@@ -561,7 +582,9 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
561
582
|
name.className = 'jp-ClaudeSessionsPanel-name';
|
|
562
583
|
name.textContent = this._lookupName(session);
|
|
563
584
|
row.appendChild(name);
|
|
564
|
-
|
|
585
|
+
// No star in the Favourites section - every row there is a favourite
|
|
586
|
+
// by definition; stars are an indicator only useful in Recent/All.
|
|
587
|
+
if (session.favourite && sectionKey !== 'favourites') {
|
|
565
588
|
const star = document.createElement('span');
|
|
566
589
|
star.className = 'jp-ClaudeSessionsPanel-favStar';
|
|
567
590
|
star.title = 'Favourite';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_claude_code_extension",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.32",
|
|
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/icons.ts
CHANGED
|
@@ -51,7 +51,7 @@ export const removeIcon = new LabIcon({
|
|
|
51
51
|
svgstr: removeSvgStr
|
|
52
52
|
});
|
|
53
53
|
|
|
54
|
-
const shieldSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="
|
|
54
|
+
const shieldSvgStr = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="13" height="13">
|
|
55
55
|
<path class="jp-icon3" fill="#616161" d="M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 10.99h7c-.53 4.12-3.28 7.79-7 8.94V12H5V6.3l7-3.11v8.8z"/>
|
|
56
56
|
</svg>`;
|
|
57
57
|
|
package/src/widget.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { JupyterFrontEnd } from '@jupyterlab/application';
|
|
2
|
+
import { Dialog, showDialog } from '@jupyterlab/apputils';
|
|
2
3
|
import { ServerConnection } from '@jupyterlab/services';
|
|
3
4
|
import { ITerminalTracker } from '@jupyterlab/terminal';
|
|
4
5
|
import { CommandRegistry } from '@lumino/commands';
|
|
@@ -379,22 +380,34 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
379
380
|
forceDangerous: boolean
|
|
380
381
|
): Promise<void> {
|
|
381
382
|
try {
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
//
|
|
383
|
+
// Always prefer reusing an open terminal for this project. The
|
|
384
|
+
// skip-permissions flag can only be applied to a fresh pty, never
|
|
385
|
+
// retroactively. So if the user wants dangerous mode but an open
|
|
386
|
+
// terminal already exists, show a modal asking them to close it
|
|
387
|
+
// first - we won't auto-close, won't silently reuse the wrong mode.
|
|
388
|
+
|
|
389
|
+
// 1. In-memory microcache.
|
|
385
390
|
const cached = this._terminalsByPath.get(session.project_path);
|
|
386
391
|
if (cached && !cached.isDisposed) {
|
|
392
|
+
if (forceDangerous) {
|
|
393
|
+
await this._showCloseExistingDialog();
|
|
394
|
+
this._app.shell.activateById(cached.id);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
387
397
|
this._app.shell.activateById(cached.id);
|
|
388
398
|
return;
|
|
389
399
|
}
|
|
390
400
|
|
|
391
|
-
// 2. Walk every live terminal widget JL knows about
|
|
392
|
-
// server for the cwd of EVERY process in its pty's tree. Match if
|
|
393
|
-
// any one of them equals project_path.
|
|
401
|
+
// 2. Walk every live terminal widget JL knows about.
|
|
394
402
|
const found = await this._findTerminalForCwd(session.project_path);
|
|
395
403
|
if (found) {
|
|
396
404
|
this._terminalsByPath.set(session.project_path, found);
|
|
397
405
|
this._wireTerminalDisposal(session.project_path, found);
|
|
406
|
+
if (forceDangerous) {
|
|
407
|
+
await this._showCloseExistingDialog();
|
|
408
|
+
this._app.shell.activateById(found.id);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
398
411
|
this._app.shell.activateById(found.id);
|
|
399
412
|
return;
|
|
400
413
|
}
|
|
@@ -464,6 +477,17 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
464
477
|
return null;
|
|
465
478
|
}
|
|
466
479
|
|
|
480
|
+
private async _showCloseExistingDialog(): Promise<void> {
|
|
481
|
+
await showDialog({
|
|
482
|
+
title: 'Existing Claude session is running',
|
|
483
|
+
body:
|
|
484
|
+
'A terminal for this project is already open. To launch with ' +
|
|
485
|
+
'--dangerously-skip-permissions, close that terminal first then ' +
|
|
486
|
+
'click "Resume (Skip Permissions)" again.',
|
|
487
|
+
buttons: [Dialog.okButton({ label: 'OK' })]
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
|
|
467
491
|
private _wireTerminalDisposal(projectPath: string, widget: any): void {
|
|
468
492
|
if (!widget?.disposed?.connect) {
|
|
469
493
|
return;
|
|
@@ -625,7 +649,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
625
649
|
list.appendChild(empty);
|
|
626
650
|
} else {
|
|
627
651
|
for (const item of items) {
|
|
628
|
-
list.appendChild(this._renderRow(item));
|
|
652
|
+
list.appendChild(this._renderRow(item, key));
|
|
629
653
|
}
|
|
630
654
|
}
|
|
631
655
|
section.appendChild(list);
|
|
@@ -634,7 +658,7 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
634
658
|
this._bodyEl.appendChild(section);
|
|
635
659
|
}
|
|
636
660
|
|
|
637
|
-
private _renderRow(session: ISession): HTMLDivElement {
|
|
661
|
+
private _renderRow(session: ISession, sectionKey: SectionKey): HTMLDivElement {
|
|
638
662
|
const row = document.createElement('div');
|
|
639
663
|
row.className = 'jp-ClaudeSessionsPanel-row';
|
|
640
664
|
row.title = this._buildRowTooltip(session);
|
|
@@ -665,7 +689,9 @@ export class ClaudeCodeSessionsWidget extends Widget {
|
|
|
665
689
|
name.textContent = this._lookupName(session);
|
|
666
690
|
row.appendChild(name);
|
|
667
691
|
|
|
668
|
-
|
|
692
|
+
// No star in the Favourites section - every row there is a favourite
|
|
693
|
+
// by definition; stars are an indicator only useful in Recent/All.
|
|
694
|
+
if (session.favourite && sectionKey !== 'favourites') {
|
|
669
695
|
const star = document.createElement('span');
|
|
670
696
|
star.className = 'jp-ClaudeSessionsPanel-favStar';
|
|
671
697
|
star.title = 'Favourite';
|