jupyterlab_ai_code_assistants_extension 1.2.35 → 1.2.38
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 +1 -1
- package/lib/core/panel.d.ts +1 -21
- package/lib/core/panel.js +20 -59
- package/lib/core/types.d.ts +2 -1
- package/lib/providers/claude.js +3 -3
- package/package.json +1 -1
- package/src/__tests__/panel.spec.ts +7 -5
- package/src/core/panel.ts +22 -64
- package/src/core/types.ts +2 -1
- package/src/providers/claude.ts +3 -3
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ Chat-panel extensions re-implement the agent loop and trail the real tool. This
|
|
|
41
41
|
- **Favorites** - star projects you keep coming back to via the right-click menu; favourites from the standalone extensions are migrated on first run
|
|
42
42
|
- **Remove and clean up** - drop a project's history or a project's extra parallel sessions from the right-click menu, confirmation dialog first; removed files honour JupyterLab's "move files to trash" setting
|
|
43
43
|
- **Activity at a glance** - each row shows its last activity in an aligned column; rows active within the last minute light up, rows idle for over a week dim, and rows with parallel conversations show a branch icon with the count
|
|
44
|
-
- **Remote control indicator and background agents** (Claude) - a green dot marks sessions actively under remote control, and a conversation held by a running background agent shows a `bg` chip; clicking
|
|
44
|
+
- **Remote control indicator and background agents** (Claude) - a green dot marks sessions actively under remote control, and a conversation held by a running background agent shows a `bg` chip; clicking stops the agent and resumes the same conversation in your terminal, so it becomes an ordinary interactive session
|
|
45
45
|
- **Search** - fuzzy filter per panel, toggled by the funnel button
|
|
46
46
|
- **Presentation modes** - label rows by session name or by path relative to the JupyterLab root
|
|
47
47
|
- **Conflict-safe upgrade** - if a retired standalone extension is still installed, its panel wins and this extension stands down for that assistant instead of showing a duplicate
|
package/lib/core/panel.d.ts
CHANGED
|
@@ -252,24 +252,6 @@ export declare class AssistantSessionsPanel extends Widget {
|
|
|
252
252
|
* that build a byte-identical launch, and the unmarked one is the default
|
|
253
253
|
* the user clicks. */
|
|
254
254
|
private _resolvedVariant;
|
|
255
|
-
/** The same mode as it applies to RESUME - of the active row by default, or
|
|
256
|
-
* of whichever conversation is named.
|
|
257
|
-
*
|
|
258
|
-
* An attach is not a launch: the server returns the argv before the flag is
|
|
259
|
-
* appended, deliberately, so promising the mode on a conversation a live
|
|
260
|
-
* worker already holds would name something the assistant never receives.
|
|
261
|
-
* That is true of resuming and of nothing else, so it is tested HERE rather
|
|
262
|
-
* than in `_resolvedVariant` - which is read by the `+` button and both
|
|
263
|
-
* new-session and branch items, none of which attach. Testing it there let
|
|
264
|
-
* one right-click on a background-agent row strip the mode's name off every
|
|
265
|
-
* one of those surfaces panel-wide, while their launches went on carrying it
|
|
266
|
-
* (DEF-37).
|
|
267
|
-
*
|
|
268
|
-
* The argument is what lets a surface that describes SOMEONE ELSE'S resume -
|
|
269
|
-
* a row tooltip built during a render, a branch item in the submenu - ask the
|
|
270
|
-
* question about that conversation rather than about the active row.
|
|
271
|
-
*/
|
|
272
|
-
private _resumeVariant;
|
|
273
255
|
/** The variant suffix a plain item wears while that mode is in force. */
|
|
274
256
|
private _variantSuffix;
|
|
275
257
|
/** Whether a forced variant would build the launch the plain item already
|
|
@@ -311,9 +293,7 @@ export declare class AssistantSessionsPanel extends Widget {
|
|
|
311
293
|
private _openManagePopup;
|
|
312
294
|
/** Tooltip for one Open button in the Manage Sessions popup. Same rule as the
|
|
313
295
|
* Open Branched Conversation submenu: the button launches a terminal, so it
|
|
314
|
-
* names the mode that launch carries
|
|
315
|
-
* is attached to and carries none. The row's own conversation is not in
|
|
316
|
-
* `_lastBranches`, so it answers from the session. */
|
|
296
|
+
* names the mode that launch carries. */
|
|
317
297
|
private _openBranchTitle;
|
|
318
298
|
/** The live-worker chip for a branch row, when the provider has workers at
|
|
319
299
|
* all. Returning null lets the popup fall back to its fork marker. */
|
package/lib/core/panel.js
CHANGED
|
@@ -1593,9 +1593,9 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
1593
1593
|
badge.appendChild(document.createTextNode(String(session.extra_sessions + 1)));
|
|
1594
1594
|
name.appendChild(badge);
|
|
1595
1595
|
}
|
|
1596
|
-
// A live worker owns this conversation, so a click
|
|
1597
|
-
// resuming
|
|
1598
|
-
//
|
|
1596
|
+
// A live worker owns this conversation, so a click stops it before
|
|
1597
|
+
// resuming. Marked so the difference is visible before the click, not a
|
|
1598
|
+
// surprise after it. No own title: a child title shadows the
|
|
1599
1599
|
// row's, which would hide the path behind a two-character chip.
|
|
1600
1600
|
if (this._descriptor.hasBgAgents && session.bg_id) {
|
|
1601
1601
|
const bg = document.createElement('span');
|
|
@@ -1767,15 +1767,10 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
1767
1767
|
lines.push('Status: active');
|
|
1768
1768
|
}
|
|
1769
1769
|
if (this._descriptor.hasBgAgents && s.bg_id) {
|
|
1770
|
-
lines.push(`Background agent: ${s.bg_id} (click
|
|
1770
|
+
lines.push(`Background agent: ${s.bg_id} (click stops it and resumes here)`);
|
|
1771
1771
|
}
|
|
1772
1772
|
lines.push(...((_c = (_b = (_a = this._hooks).tooltipLines) === null || _b === void 0 ? void 0 : _b.call(_a, s)) !== null && _c !== void 0 ? _c : []));
|
|
1773
|
-
|
|
1774
|
-
// the line above may have just said the click joins a live worker, and an
|
|
1775
|
-
// attach is issued before the mode is appended, so `_resolvedVariant`
|
|
1776
|
-
// promised a flag the server discards - one tooltip naming both, a line
|
|
1777
|
-
// apart (DEF-46).
|
|
1778
|
-
const variant = this._resumeVariant(s);
|
|
1773
|
+
const variant = this._resolvedVariant();
|
|
1779
1774
|
if (variant) {
|
|
1780
1775
|
// The row click launches with this, and the menu is the only other place
|
|
1781
1776
|
// that says so.
|
|
@@ -1891,27 +1886,6 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
1891
1886
|
const resolved = resolvedLaunchModeEntry(this._descriptor.launchModes, this._modes);
|
|
1892
1887
|
return resolved;
|
|
1893
1888
|
}
|
|
1894
|
-
/** The same mode as it applies to RESUME - of the active row by default, or
|
|
1895
|
-
* of whichever conversation is named.
|
|
1896
|
-
*
|
|
1897
|
-
* An attach is not a launch: the server returns the argv before the flag is
|
|
1898
|
-
* appended, deliberately, so promising the mode on a conversation a live
|
|
1899
|
-
* worker already holds would name something the assistant never receives.
|
|
1900
|
-
* That is true of resuming and of nothing else, so it is tested HERE rather
|
|
1901
|
-
* than in `_resolvedVariant` - which is read by the `+` button and both
|
|
1902
|
-
* new-session and branch items, none of which attach. Testing it there let
|
|
1903
|
-
* one right-click on a background-agent row strip the mode's name off every
|
|
1904
|
-
* one of those surfaces panel-wide, while their launches went on carrying it
|
|
1905
|
-
* (DEF-37).
|
|
1906
|
-
*
|
|
1907
|
-
* The argument is what lets a surface that describes SOMEONE ELSE'S resume -
|
|
1908
|
-
* a row tooltip built during a render, a branch item in the submenu - ask the
|
|
1909
|
-
* question about that conversation rather than about the active row.
|
|
1910
|
-
*/
|
|
1911
|
-
_resumeVariant(target = this._activeSession) {
|
|
1912
|
-
const joining = this._descriptor.hasBgAgents && !!(target === null || target === void 0 ? void 0 : target.bg_id);
|
|
1913
|
-
return joining ? null : this._resolvedVariant();
|
|
1914
|
-
}
|
|
1915
1889
|
/** The variant suffix a plain item wears while that mode is in force. */
|
|
1916
1890
|
_variantSuffix() {
|
|
1917
1891
|
const resolved = this._resolvedVariant();
|
|
@@ -1951,16 +1925,15 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
1951
1925
|
}
|
|
1952
1926
|
});
|
|
1953
1927
|
this._commands.addCommand(this._cmd('resume'), {
|
|
1954
|
-
//
|
|
1955
|
-
//
|
|
1956
|
-
// gets.
|
|
1928
|
+
// Resuming a conversation a live worker holds stops that worker first,
|
|
1929
|
+
// so a provider that has workers says which of the two this row gets.
|
|
1957
1930
|
label: () => {
|
|
1958
1931
|
var _a, _b, _c;
|
|
1959
|
-
const variant = this.
|
|
1932
|
+
const variant = this._resolvedVariant();
|
|
1960
1933
|
const verb = (_c = (_b = (_a = this._hooks).resumeLabel) === null || _b === void 0 ? void 0 : _b.call(_a, active())) !== null && _c !== void 0 ? _c : 'Resume';
|
|
1961
1934
|
return variant ? `${verb} (${variant.label})` : verb;
|
|
1962
1935
|
},
|
|
1963
|
-
icon: () => { var _a; return (((_a = this.
|
|
1936
|
+
icon: () => { var _a; return (((_a = this._resolvedVariant()) === null || _a === void 0 ? void 0 : _a.unsafe) ? shieldIcon : undefined); },
|
|
1964
1937
|
execute: () => {
|
|
1965
1938
|
const s = active();
|
|
1966
1939
|
if (s) {
|
|
@@ -1970,15 +1943,13 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
1970
1943
|
});
|
|
1971
1944
|
for (const mode of this._variantModes) {
|
|
1972
1945
|
this._commands.addCommand(this._cmd(`resume-${mode.id}`), {
|
|
1973
|
-
|
|
1946
|
+
// The same verb as the plain item, so a row a live worker holds says
|
|
1947
|
+
// here too that the worker is stopped first.
|
|
1948
|
+
label: () => { var _a, _b, _c; return `${(_c = (_b = (_a = this._hooks).resumeLabel) === null || _b === void 0 ? void 0 : _b.call(_a, active())) !== null && _c !== void 0 ? _c : 'Resume'} (${mode.menuLabel})`; },
|
|
1974
1949
|
icon: shieldIcon,
|
|
1975
1950
|
// Absent while the plain item already resolves to this same mode - it
|
|
1976
1951
|
// would be a second entry building an identical launch.
|
|
1977
1952
|
isVisible: () => !this._buildsSameLaunch(mode),
|
|
1978
|
-
// A conversation a live worker already holds was started in whatever
|
|
1979
|
-
// mode that worker has; joining it cannot change that, so the variant
|
|
1980
|
-
// is disabled rather than silently joining in the wrong mode.
|
|
1981
|
-
isEnabled: () => { var _a; return !(this._descriptor.hasBgAgents && ((_a = active()) === null || _a === void 0 ? void 0 : _a.bg_id)); },
|
|
1982
1953
|
execute: () => {
|
|
1983
1954
|
const s = active();
|
|
1984
1955
|
if (s) {
|
|
@@ -2127,13 +2098,11 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2127
2098
|
this._commands.addCommand(this._cmd('open-branch'), {
|
|
2128
2099
|
// Names the mode the launch carries, like Resume, `+` and Branch Session
|
|
2129
2100
|
// do - this item opens a terminal, so the mode in force applies to it and
|
|
2130
|
-
// this was the one launch surface that stayed silent about it.
|
|
2131
|
-
// aware per conversation: the submenu passes `bg`, since a branch a live
|
|
2132
|
-
// worker holds is attached to and takes no mode (DEF-46's rule).
|
|
2101
|
+
// this was the one launch surface that stayed silent about it.
|
|
2133
2102
|
label: args => {
|
|
2134
2103
|
var _a;
|
|
2135
2104
|
const base = String((_a = args.label) !== null && _a !== void 0 ? _a : '');
|
|
2136
|
-
const variant = this.
|
|
2105
|
+
const variant = this._resolvedVariant();
|
|
2137
2106
|
return variant ? `${base} (${variant.label})` : base;
|
|
2138
2107
|
},
|
|
2139
2108
|
// Intent glyph, not row state - see switch-branch above.
|
|
@@ -2436,10 +2405,7 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2436
2405
|
command: this._cmd('open-branch'),
|
|
2437
2406
|
args: {
|
|
2438
2407
|
session_id: b.session_id,
|
|
2439
|
-
label: this._branchMenuLabel(b)
|
|
2440
|
-
// The label reads this to tell an attach from a launch; the
|
|
2441
|
-
// provider's own worker capability is tested where it is answered.
|
|
2442
|
-
...(b.bg_id ? { bg: b.bg_id } : {})
|
|
2408
|
+
label: this._branchMenuLabel(b)
|
|
2443
2409
|
}
|
|
2444
2410
|
});
|
|
2445
2411
|
}
|
|
@@ -2463,7 +2429,7 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2463
2429
|
branchName: b => this._branchDisplayName(b),
|
|
2464
2430
|
formatTime: ms => this._formatRelativeTime(ms),
|
|
2465
2431
|
branchBadge: b => this._bgBadgeFor(b),
|
|
2466
|
-
openTitle:
|
|
2432
|
+
openTitle: () => this._openBranchTitle(session),
|
|
2467
2433
|
onSwitch: id => void this._switchBranch(session, id),
|
|
2468
2434
|
onOpen: id => void this._openSession(session, undefined, id),
|
|
2469
2435
|
onDelete: ids => this._deleteBranches(session, ids),
|
|
@@ -2475,21 +2441,16 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2475
2441
|
}
|
|
2476
2442
|
/** Tooltip for one Open button in the Manage Sessions popup. Same rule as the
|
|
2477
2443
|
* Open Branched Conversation submenu: the button launches a terminal, so it
|
|
2478
|
-
* names the mode that launch carries
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
_openBranchTitle(session, sessionId) {
|
|
2482
|
-
var _a, _b, _c, _d;
|
|
2444
|
+
* names the mode that launch carries. */
|
|
2445
|
+
_openBranchTitle(session) {
|
|
2446
|
+
var _a, _b, _c;
|
|
2483
2447
|
// One terminal serves a project-scoped assistant, so the button focuses
|
|
2484
2448
|
// or starts it, under the provider's own verb for that.
|
|
2485
2449
|
if (this._descriptor.terminalScope === 'project') {
|
|
2486
2450
|
return ((_c = (_b = (_a = this._hooks).resumeLabel) === null || _b === void 0 ? void 0 : _b.call(_a, session)) !== null && _c !== void 0 ? _c : "Open the project's terminal");
|
|
2487
2451
|
}
|
|
2488
2452
|
const base = 'Open this conversation in its own terminal';
|
|
2489
|
-
const
|
|
2490
|
-
? session
|
|
2491
|
-
: ((_d = this._lastBranches.find(b => b.session_id === sessionId)) !== null && _d !== void 0 ? _d : null);
|
|
2492
|
-
const variant = this._resumeVariant(target);
|
|
2453
|
+
const variant = this._resolvedVariant();
|
|
2493
2454
|
return variant ? `${base} (${variant.label})` : base;
|
|
2494
2455
|
}
|
|
2495
2456
|
/** The live-worker chip for a branch row, when the provider has workers at
|
package/lib/core/types.d.ts
CHANGED
|
@@ -309,7 +309,8 @@ export interface ITabColourEvents {
|
|
|
309
309
|
* shared panel. */
|
|
310
310
|
export interface IProviderHooks {
|
|
311
311
|
/** Label for the primary open action, when the provider distinguishes verbs
|
|
312
|
-
* (
|
|
312
|
+
* (stopping a live worker before resuming is not the same as resuming a
|
|
313
|
+
* dormant store entry). */
|
|
313
314
|
resumeLabel?: (session: ISession | null) => string;
|
|
314
315
|
/** Extra lines for the row tooltip. */
|
|
315
316
|
tooltipLines?: (session: ISession) => string[];
|
package/lib/providers/claude.js
CHANGED
|
@@ -70,7 +70,7 @@ export const descriptor = {
|
|
|
70
70
|
legacyPluginId: 'jupyterlab_claude_code_extension'
|
|
71
71
|
};
|
|
72
72
|
export const hooks = {
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
resumeLabel: (session) => (session === null || session === void 0 ? void 0 : session.bg_id) ? '
|
|
73
|
+
// Opening a conversation a live agent holds stops the agent first, so the
|
|
74
|
+
// item says so before the click (DEF-PROV-272).
|
|
75
|
+
resumeLabel: (session) => (session === null || session === void 0 ? void 0 : session.bg_id) ? 'Stop Background Agent and Resume' : 'Resume'
|
|
76
76
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jupyterlab_ai_code_assistants_extension",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.38",
|
|
4
4
|
"description": "A full launcher and manager for every AI code assistant in JupyterLab - Claude Code, Codex, Kimi, Gemini and DeepSeek. Start, resume, fork, switch, and clean up CLI sessions from a side panel per assistant - one click lands you in the right terminal with the assistant already running, no duplicate tabs, no UUID hunting.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -645,13 +645,15 @@ describe('DEF-46 - the row tooltip names only a mode the row launches with', ()
|
|
|
645
645
|
expect(tooltip([session()])).toContain('Launch mode: Skip Permissions');
|
|
646
646
|
});
|
|
647
647
|
|
|
648
|
-
it('
|
|
648
|
+
it('names the mode on a row a live worker holds, which is resumed too', () => {
|
|
649
649
|
panel.setModes({ skip: true });
|
|
650
|
-
//
|
|
651
|
-
//
|
|
650
|
+
// The click stops the worker and resumes the conversation, and a resume
|
|
651
|
+
// carries the mode (DEF-PROV-272).
|
|
652
652
|
const text = tooltip([session({ bg_id: 'abcd1234' })]);
|
|
653
|
-
expect(text).toContain(
|
|
654
|
-
|
|
653
|
+
expect(text).toContain(
|
|
654
|
+
'Background agent: abcd1234 (click stops it and resumes here)'
|
|
655
|
+
);
|
|
656
|
+
expect(text).toContain('Launch mode: Skip Permissions');
|
|
655
657
|
});
|
|
656
658
|
});
|
|
657
659
|
|
package/src/core/panel.ts
CHANGED
|
@@ -1899,9 +1899,9 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
1899
1899
|
);
|
|
1900
1900
|
name.appendChild(badge);
|
|
1901
1901
|
}
|
|
1902
|
-
// A live worker owns this conversation, so a click
|
|
1903
|
-
// resuming
|
|
1904
|
-
//
|
|
1902
|
+
// A live worker owns this conversation, so a click stops it before
|
|
1903
|
+
// resuming. Marked so the difference is visible before the click, not a
|
|
1904
|
+
// surprise after it. No own title: a child title shadows the
|
|
1905
1905
|
// row's, which would hide the path behind a two-character chip.
|
|
1906
1906
|
if (this._descriptor.hasBgAgents && session.bg_id) {
|
|
1907
1907
|
const bg = document.createElement('span');
|
|
@@ -2086,15 +2086,12 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2086
2086
|
lines.push('Status: active');
|
|
2087
2087
|
}
|
|
2088
2088
|
if (this._descriptor.hasBgAgents && s.bg_id) {
|
|
2089
|
-
lines.push(
|
|
2089
|
+
lines.push(
|
|
2090
|
+
`Background agent: ${s.bg_id} (click stops it and resumes here)`
|
|
2091
|
+
);
|
|
2090
2092
|
}
|
|
2091
2093
|
lines.push(...(this._hooks.tooltipLines?.(s) ?? []));
|
|
2092
|
-
|
|
2093
|
-
// the line above may have just said the click joins a live worker, and an
|
|
2094
|
-
// attach is issued before the mode is appended, so `_resolvedVariant`
|
|
2095
|
-
// promised a flag the server discards - one tooltip naming both, a line
|
|
2096
|
-
// apart (DEF-46).
|
|
2097
|
-
const variant = this._resumeVariant(s);
|
|
2094
|
+
const variant = this._resolvedVariant();
|
|
2098
2095
|
if (variant) {
|
|
2099
2096
|
// The row click launches with this, and the menu is the only other place
|
|
2100
2097
|
// that says so.
|
|
@@ -2230,30 +2227,6 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2230
2227
|
return resolved;
|
|
2231
2228
|
}
|
|
2232
2229
|
|
|
2233
|
-
/** The same mode as it applies to RESUME - of the active row by default, or
|
|
2234
|
-
* of whichever conversation is named.
|
|
2235
|
-
*
|
|
2236
|
-
* An attach is not a launch: the server returns the argv before the flag is
|
|
2237
|
-
* appended, deliberately, so promising the mode on a conversation a live
|
|
2238
|
-
* worker already holds would name something the assistant never receives.
|
|
2239
|
-
* That is true of resuming and of nothing else, so it is tested HERE rather
|
|
2240
|
-
* than in `_resolvedVariant` - which is read by the `+` button and both
|
|
2241
|
-
* new-session and branch items, none of which attach. Testing it there let
|
|
2242
|
-
* one right-click on a background-agent row strip the mode's name off every
|
|
2243
|
-
* one of those surfaces panel-wide, while their launches went on carrying it
|
|
2244
|
-
* (DEF-37).
|
|
2245
|
-
*
|
|
2246
|
-
* The argument is what lets a surface that describes SOMEONE ELSE'S resume -
|
|
2247
|
-
* a row tooltip built during a render, a branch item in the submenu - ask the
|
|
2248
|
-
* question about that conversation rather than about the active row.
|
|
2249
|
-
*/
|
|
2250
|
-
private _resumeVariant(
|
|
2251
|
-
target: { bg_id?: string | null } | null = this._activeSession
|
|
2252
|
-
): IResolvedLaunchMode | null {
|
|
2253
|
-
const joining = this._descriptor.hasBgAgents && !!target?.bg_id;
|
|
2254
|
-
return joining ? null : this._resolvedVariant();
|
|
2255
|
-
}
|
|
2256
|
-
|
|
2257
2230
|
/** The variant suffix a plain item wears while that mode is in force. */
|
|
2258
2231
|
private _variantSuffix(): string {
|
|
2259
2232
|
const resolved = this._resolvedVariant();
|
|
@@ -2302,15 +2275,14 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2302
2275
|
});
|
|
2303
2276
|
|
|
2304
2277
|
this._commands.addCommand(this._cmd('resume'), {
|
|
2305
|
-
//
|
|
2306
|
-
//
|
|
2307
|
-
// gets.
|
|
2278
|
+
// Resuming a conversation a live worker holds stops that worker first,
|
|
2279
|
+
// so a provider that has workers says which of the two this row gets.
|
|
2308
2280
|
label: () => {
|
|
2309
|
-
const variant = this.
|
|
2281
|
+
const variant = this._resolvedVariant();
|
|
2310
2282
|
const verb = this._hooks.resumeLabel?.(active()) ?? 'Resume';
|
|
2311
2283
|
return variant ? `${verb} (${variant.label})` : verb;
|
|
2312
2284
|
},
|
|
2313
|
-
icon: () => (this.
|
|
2285
|
+
icon: () => (this._resolvedVariant()?.unsafe ? shieldIcon : undefined),
|
|
2314
2286
|
execute: () => {
|
|
2315
2287
|
const s = active();
|
|
2316
2288
|
if (s) {
|
|
@@ -2321,15 +2293,14 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2321
2293
|
|
|
2322
2294
|
for (const mode of this._variantModes) {
|
|
2323
2295
|
this._commands.addCommand(this._cmd(`resume-${mode.id}`), {
|
|
2324
|
-
|
|
2296
|
+
// The same verb as the plain item, so a row a live worker holds says
|
|
2297
|
+
// here too that the worker is stopped first.
|
|
2298
|
+
label: () =>
|
|
2299
|
+
`${this._hooks.resumeLabel?.(active()) ?? 'Resume'} (${mode.menuLabel})`,
|
|
2325
2300
|
icon: shieldIcon,
|
|
2326
2301
|
// Absent while the plain item already resolves to this same mode - it
|
|
2327
2302
|
// would be a second entry building an identical launch.
|
|
2328
2303
|
isVisible: () => !this._buildsSameLaunch(mode),
|
|
2329
|
-
// A conversation a live worker already holds was started in whatever
|
|
2330
|
-
// mode that worker has; joining it cannot change that, so the variant
|
|
2331
|
-
// is disabled rather than silently joining in the wrong mode.
|
|
2332
|
-
isEnabled: () => !(this._descriptor.hasBgAgents && active()?.bg_id),
|
|
2333
2304
|
execute: () => {
|
|
2334
2305
|
const s = active();
|
|
2335
2306
|
if (s) {
|
|
@@ -2502,14 +2473,10 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2502
2473
|
this._commands.addCommand(this._cmd('open-branch'), {
|
|
2503
2474
|
// Names the mode the launch carries, like Resume, `+` and Branch Session
|
|
2504
2475
|
// do - this item opens a terminal, so the mode in force applies to it and
|
|
2505
|
-
// this was the one launch surface that stayed silent about it.
|
|
2506
|
-
// aware per conversation: the submenu passes `bg`, since a branch a live
|
|
2507
|
-
// worker holds is attached to and takes no mode (DEF-46's rule).
|
|
2476
|
+
// this was the one launch surface that stayed silent about it.
|
|
2508
2477
|
label: args => {
|
|
2509
2478
|
const base = String(args.label ?? '');
|
|
2510
|
-
const variant = this.
|
|
2511
|
-
args.bg ? { bg_id: String(args.bg) } : null
|
|
2512
|
-
);
|
|
2479
|
+
const variant = this._resolvedVariant();
|
|
2513
2480
|
return variant ? `${base} (${variant.label})` : base;
|
|
2514
2481
|
},
|
|
2515
2482
|
// Intent glyph, not row state - see switch-branch above.
|
|
@@ -2844,10 +2811,7 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2844
2811
|
command: this._cmd('open-branch'),
|
|
2845
2812
|
args: {
|
|
2846
2813
|
session_id: b.session_id,
|
|
2847
|
-
label: this._branchMenuLabel(b)
|
|
2848
|
-
// The label reads this to tell an attach from a launch; the
|
|
2849
|
-
// provider's own worker capability is tested where it is answered.
|
|
2850
|
-
...(b.bg_id ? { bg: b.bg_id } : {})
|
|
2814
|
+
label: this._branchMenuLabel(b)
|
|
2851
2815
|
}
|
|
2852
2816
|
});
|
|
2853
2817
|
}
|
|
@@ -2875,7 +2839,7 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2875
2839
|
branchName: b => this._branchDisplayName(b),
|
|
2876
2840
|
formatTime: ms => this._formatRelativeTime(ms),
|
|
2877
2841
|
branchBadge: b => this._bgBadgeFor(b),
|
|
2878
|
-
openTitle:
|
|
2842
|
+
openTitle: () => this._openBranchTitle(session),
|
|
2879
2843
|
onSwitch: id => void this._switchBranch(session, id),
|
|
2880
2844
|
onOpen: id => void this._openSession(session, undefined, id),
|
|
2881
2845
|
onDelete: ids => this._deleteBranches(session, ids),
|
|
@@ -2888,10 +2852,8 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2888
2852
|
|
|
2889
2853
|
/** Tooltip for one Open button in the Manage Sessions popup. Same rule as the
|
|
2890
2854
|
* Open Branched Conversation submenu: the button launches a terminal, so it
|
|
2891
|
-
* names the mode that launch carries
|
|
2892
|
-
|
|
2893
|
-
* `_lastBranches`, so it answers from the session. */
|
|
2894
|
-
private _openBranchTitle(session: ISession, sessionId: string): string {
|
|
2855
|
+
* names the mode that launch carries. */
|
|
2856
|
+
private _openBranchTitle(session: ISession): string {
|
|
2895
2857
|
// One terminal serves a project-scoped assistant, so the button focuses
|
|
2896
2858
|
// or starts it, under the provider's own verb for that.
|
|
2897
2859
|
if (this._descriptor.terminalScope === 'project') {
|
|
@@ -2900,11 +2862,7 @@ export class AssistantSessionsPanel extends Widget {
|
|
|
2900
2862
|
);
|
|
2901
2863
|
}
|
|
2902
2864
|
const base = 'Open this conversation in its own terminal';
|
|
2903
|
-
const
|
|
2904
|
-
sessionId === session.session_id
|
|
2905
|
-
? session
|
|
2906
|
-
: (this._lastBranches.find(b => b.session_id === sessionId) ?? null);
|
|
2907
|
-
const variant = this._resumeVariant(target);
|
|
2865
|
+
const variant = this._resolvedVariant();
|
|
2908
2866
|
return variant ? `${base} (${variant.label})` : base;
|
|
2909
2867
|
}
|
|
2910
2868
|
|
package/src/core/types.ts
CHANGED
|
@@ -349,7 +349,8 @@ export interface ITabColourEvents {
|
|
|
349
349
|
* shared panel. */
|
|
350
350
|
export interface IProviderHooks {
|
|
351
351
|
/** Label for the primary open action, when the provider distinguishes verbs
|
|
352
|
-
* (
|
|
352
|
+
* (stopping a live worker before resuming is not the same as resuming a
|
|
353
|
+
* dormant store entry). */
|
|
353
354
|
resumeLabel?: (session: ISession | null) => string;
|
|
354
355
|
/** Extra lines for the row tooltip. */
|
|
355
356
|
tooltipLines?: (session: ISession) => string[];
|
package/src/providers/claude.ts
CHANGED
|
@@ -76,8 +76,8 @@ export const descriptor: IProviderDescriptor = {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
export const hooks: IProviderHooks = {
|
|
79
|
-
//
|
|
80
|
-
//
|
|
79
|
+
// Opening a conversation a live agent holds stops the agent first, so the
|
|
80
|
+
// item says so before the click (DEF-PROV-272).
|
|
81
81
|
resumeLabel: (session: ISession | null) =>
|
|
82
|
-
session?.bg_id ? '
|
|
82
|
+
session?.bg_id ? 'Stop Background Agent and Resume' : 'Resume'
|
|
83
83
|
};
|