xtralab 0.15.0 → 0.15.2
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 +65 -30
- package/lib/about/icons.d.ts +0 -5
- package/lib/about/icons.js +0 -5
- package/lib/about/index.d.ts +4 -8
- package/lib/about/index.js +6 -17
- package/lib/agentSessions.d.ts +9 -29
- package/lib/agentSessions.js +2 -7
- package/lib/askAgent/editorSelection.d.ts +20 -26
- package/lib/askAgent/editorSelection.js +11 -26
- package/lib/askAgent/icons.d.ts +2 -3
- package/lib/askAgent/icons.js +2 -3
- package/lib/askAgent/index.d.ts +4 -26
- package/lib/askAgent/index.js +54 -158
- package/lib/askAgent/popup.d.ts +12 -16
- package/lib/askAgent/popup.js +18 -37
- package/lib/askAgent/prompt.d.ts +3 -5
- package/lib/askAgent/prompt.js +6 -19
- package/lib/askAgent/queue.d.ts +11 -21
- package/lib/askAgent/queue.js +9 -19
- package/lib/askAgent/queuePanel.d.ts +13 -18
- package/lib/askAgent/queuePanel.js +15 -37
- package/lib/askAgent/targetPicker.d.ts +2 -9
- package/lib/askAgent/targetPicker.js +6 -11
- package/lib/askAgent/tokens.d.ts +32 -46
- package/lib/askAgent/tokens.js +4 -6
- package/lib/commandBar/index.d.ts +4 -13
- package/lib/commandBar/index.js +21 -39
- package/lib/customPanel/index.js +15 -0
- package/lib/editorBreadcrumbs/index.d.ts +3 -6
- package/lib/editorBreadcrumbs/index.js +10 -6
- package/lib/editorBreadcrumbs/widget.d.ts +17 -4
- package/lib/editorBreadcrumbs/widget.js +11 -17
- package/lib/editorIndent/index.d.ts +4 -12
- package/lib/editorIndent/index.js +8 -23
- package/lib/fileBrowser/commands.d.ts +29 -19
- package/lib/fileBrowser/commands.js +83 -97
- package/lib/fileBrowser/contents.d.ts +3 -0
- package/lib/fileBrowser/dragAndDrop.d.ts +17 -4
- package/lib/fileBrowser/dragAndDrop.js +2 -7
- package/lib/fileBrowser/fileBrowser.d.ts +19 -9
- package/lib/fileBrowser/fileBrowser.js +70 -222
- package/lib/fileBrowser/gitStatus.d.ts +16 -10
- package/lib/fileBrowser/gitStatus.js +31 -30
- package/lib/fileBrowser/gitignore.d.ts +4 -17
- package/lib/fileBrowser/gitignore.js +4 -25
- package/lib/fileBrowser/icons.d.ts +7 -17
- package/lib/fileBrowser/icons.js +25 -80
- package/lib/fileBrowser/index.js +2 -4
- package/lib/fileBrowser/widget.d.ts +141 -48
- package/lib/fileBrowser/widget.js +102 -4
- package/lib/fileTypeIcons/index.js +0 -10
- package/lib/git/api.d.ts +5 -13
- package/lib/git/api.js +10 -36
- package/lib/git/askRequest.d.ts +4 -8
- package/lib/git/askRequest.js +6 -20
- package/lib/git/commands.d.ts +45 -5
- package/lib/git/commands.js +20 -13
- package/lib/git/diffModel.js +4 -0
- package/lib/git/diffPreferences.d.ts +90 -0
- package/lib/git/diffPreferences.js +107 -0
- package/lib/git/diffProvider.js +10 -2
- package/lib/git/diffSurface.d.ts +64 -63
- package/lib/git/diffSurface.js +72 -213
- package/lib/git/diffTheme.d.ts +7 -0
- package/lib/git/diffTheme.js +23 -0
- package/lib/git/diffWidget.d.ts +70 -14
- package/lib/git/diffWidget.js +100 -94
- package/lib/git/imageDiff.d.ts +14 -6
- package/lib/git/imageDiff.js +19 -75
- package/lib/git/index.d.ts +0 -3
- package/lib/git/index.js +44 -10
- package/lib/git/notebookDiff.d.ts +110 -33
- package/lib/git/notebookDiff.js +55 -197
- package/lib/git/tokens.d.ts +73 -31
- package/lib/git/tokens.js +2 -3
- package/lib/highlight/index.d.ts +4 -10
- package/lib/highlight/index.js +10 -41
- package/lib/index.d.ts +0 -9
- package/lib/index.js +0 -9
- package/lib/launcher/agents.d.ts +55 -51
- package/lib/launcher/agents.js +15 -57
- package/lib/launcher/availability.d.ts +3 -9
- package/lib/launcher/availability.js +3 -9
- package/lib/launcher/commands.d.ts +7 -32
- package/lib/launcher/commands.js +14 -45
- package/lib/launcher/dashboard.d.ts +19 -24
- package/lib/launcher/dashboard.js +21 -67
- package/lib/launcher/editorRegistry.d.ts +10 -22
- package/lib/launcher/editorRegistry.js +14 -18
- package/lib/launcher/editors.d.ts +39 -45
- package/lib/launcher/editors.js +8 -34
- package/lib/launcher/icons.d.ts +0 -12
- package/lib/launcher/icons.js +5 -39
- package/lib/launcher/index.js +12 -55
- package/lib/launcher/invocation.d.ts +4 -10
- package/lib/launcher/invocation.js +7 -22
- package/lib/launcher/registry.d.ts +9 -7
- package/lib/launcher/registry.js +9 -7
- package/lib/launcher/tokens.d.ts +10 -22
- package/lib/launcher/tokens.js +5 -8
- package/lib/menuBar/index.d.ts +3 -10
- package/lib/menuBar/index.js +11 -28
- package/lib/menus/index.d.ts +3 -9
- package/lib/menus/index.js +14 -30
- package/lib/omnibox/files.d.ts +2 -4
- package/lib/omnibox/files.js +5 -11
- package/lib/omnibox/index.d.ts +4 -14
- package/lib/omnibox/index.js +9 -27
- package/lib/omnibox/model.d.ts +38 -10
- package/lib/omnibox/model.js +15 -33
- package/lib/omnibox/recents.d.ts +15 -17
- package/lib/omnibox/recents.js +12 -17
- package/lib/omnibox/tokens.d.ts +5 -10
- package/lib/omnibox/tokens.js +2 -6
- package/lib/omnibox/widget.d.ts +11 -7
- package/lib/omnibox/widget.js +8 -16
- package/lib/searchReplace/index.d.ts +4 -20
- package/lib/searchReplace/index.js +7 -27
- package/lib/showOutput/index.d.ts +3 -12
- package/lib/showOutput/index.js +6 -22
- package/lib/sidebar/index.d.ts +4 -7
- package/lib/sidebar/index.js +5 -12
- package/lib/terminalNotifications/index.d.ts +4 -10
- package/lib/terminalNotifications/index.js +6 -20
- package/lib/terminals/agentTerminals.d.ts +12 -5
- package/lib/terminals/agentTerminals.js +25 -44
- package/lib/terminals/detection.d.ts +4 -8
- package/lib/terminals/detection.js +4 -8
- package/lib/terminals/index.d.ts +0 -35
- package/lib/terminals/index.js +12 -101
- package/lib/terminals/model.d.ts +64 -139
- package/lib/terminals/model.js +80 -220
- package/lib/terminals/tokens.d.ts +11 -22
- package/lib/terminals/tokens.js +2 -2
- package/lib/terminals/widget.d.ts +43 -13
- package/lib/terminals/widget.js +33 -18
- package/lib/topBar/icons.d.ts +3 -8
- package/lib/topBar/icons.js +3 -8
- package/lib/topBar/index.d.ts +4 -11
- package/lib/topBar/index.js +10 -38
- package/lib/walkthrough/index.d.ts +4 -9
- package/lib/walkthrough/index.js +6 -20
- package/lib/walkthrough/panel.d.ts +40 -9
- package/lib/walkthrough/panel.js +4 -10
- package/package.json +5 -3
- package/schema/git-diff-preferences.json +42 -0
- package/src/about/icons.ts +0 -5
- package/src/about/index.tsx +6 -17
- package/src/agentSessions.ts +9 -29
- package/src/askAgent/editorSelection.ts +22 -29
- package/src/askAgent/icons.ts +2 -3
- package/src/askAgent/index.ts +54 -158
- package/src/askAgent/popup.tsx +23 -45
- package/src/askAgent/prompt.ts +6 -19
- package/src/askAgent/queue.ts +13 -24
- package/src/askAgent/queuePanel.tsx +21 -46
- package/src/askAgent/targetPicker.tsx +5 -15
- package/src/askAgent/tokens.ts +32 -46
- package/src/commandBar/index.ts +24 -39
- package/src/customPanel/index.ts +15 -0
- package/src/editorBreadcrumbs/index.ts +10 -6
- package/src/editorBreadcrumbs/widget.ts +23 -17
- package/src/editorIndent/index.ts +17 -23
- package/src/fileBrowser/commands.ts +119 -96
- package/src/fileBrowser/contents.ts +3 -0
- package/src/fileBrowser/dragAndDrop.ts +17 -7
- package/src/fileBrowser/fileBrowser.tsx +86 -230
- package/src/fileBrowser/gitStatus.ts +36 -33
- package/src/fileBrowser/gitignore.ts +4 -25
- package/src/fileBrowser/icons.ts +25 -80
- package/src/fileBrowser/index.ts +2 -4
- package/src/fileBrowser/widget.tsx +171 -50
- package/src/fileTypeIcons/index.ts +0 -10
- package/src/git/api.ts +10 -36
- package/src/git/askRequest.ts +6 -20
- package/src/git/commands.ts +83 -11
- package/src/git/diffModel.ts +25 -0
- package/src/git/diffPreferences.ts +192 -0
- package/src/git/diffProvider.tsx +11 -2
- package/src/git/diffSurface.tsx +165 -286
- package/src/git/diffTheme.ts +24 -0
- package/src/git/diffWidget.tsx +194 -134
- package/src/git/imageDiff.tsx +56 -84
- package/src/git/index.ts +54 -10
- package/src/git/notebookDiff.tsx +214 -240
- package/src/git/tokens.ts +73 -31
- package/src/highlight/index.ts +10 -41
- package/src/index.ts +0 -9
- package/src/launcher/agents.ts +64 -95
- package/src/launcher/availability.ts +3 -9
- package/src/launcher/commands.ts +14 -51
- package/src/launcher/dashboard.tsx +49 -88
- package/src/launcher/editorRegistry.ts +21 -29
- package/src/launcher/editors.ts +39 -58
- package/src/launcher/icons.ts +5 -39
- package/src/launcher/index.ts +12 -55
- package/src/launcher/invocation.ts +7 -22
- package/src/launcher/registry.ts +9 -7
- package/src/launcher/tokens.ts +10 -22
- package/src/menuBar/index.ts +11 -28
- package/src/menus/index.ts +14 -30
- package/src/omnibox/files.ts +10 -14
- package/src/omnibox/index.ts +9 -27
- package/src/omnibox/model.ts +50 -38
- package/src/omnibox/recents.ts +17 -22
- package/src/omnibox/tokens.ts +5 -10
- package/src/omnibox/widget.tsx +14 -19
- package/src/searchReplace/index.ts +7 -27
- package/src/showOutput/index.ts +6 -22
- package/src/sidebar/index.ts +20 -12
- package/src/terminalNotifications/index.ts +42 -25
- package/src/terminals/agentTerminals.ts +25 -49
- package/src/terminals/detection.ts +4 -8
- package/src/terminals/index.ts +12 -101
- package/src/terminals/model.ts +130 -246
- package/src/terminals/tokens.ts +11 -22
- package/src/terminals/widget.tsx +48 -31
- package/src/topBar/icons.ts +3 -8
- package/src/topBar/index.ts +21 -44
- package/src/walkthrough/index.ts +6 -20
- package/src/walkthrough/panel.ts +40 -10
- package/style/about.css +2 -7
- package/style/askAgent.css +8 -40
- package/style/base.css +9 -45
- package/style/chrome.css +108 -308
- package/style/commandBar.css +4 -20
- package/style/customPanel.css +1 -4
- package/style/git.css +26 -186
- package/style/highlight.css +1 -3
- package/style/launcher.css +6 -70
- package/style/omnibox.css +2 -14
- package/style/showOutput.css +0 -6
- package/style/sidebar.css +29 -9
- package/style/tabs.css +5 -13
- package/style/terminals.css +6 -53
- package/style/topBar.css +2 -22
- package/style/walkthrough.css +0 -8
package/src/launcher/commands.ts
CHANGED
|
@@ -9,24 +9,13 @@ import type { IAgent } from './agents';
|
|
|
9
9
|
import { buildAgentInvocation } from './invocation';
|
|
10
10
|
import { agentCommandId } from './tokens';
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* The command id for opening the launcher.
|
|
14
|
-
*/
|
|
15
12
|
export const CREATE_LAUNCHER_COMMAND = 'launcher:create';
|
|
16
13
|
|
|
17
14
|
/**
|
|
18
|
-
* Register a JupyterLab command per agent
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* Returns a single disposable that tears down every registered command —
|
|
23
|
-
* the launcher disposes the previous set before re-registering on settings
|
|
24
|
-
* changes so the command palette stays in sync with the configured agents.
|
|
25
|
-
*
|
|
26
|
-
* When an `agentSessions` registry is supplied, each launch tags its terminal
|
|
27
|
-
* session with the agent's command, so the terminals panel can badge the row
|
|
28
|
-
* with the agent's logo immediately (before server-side detection confirms
|
|
29
|
-
* it).
|
|
15
|
+
* Register a JupyterLab command per agent that opens a new terminal and types
|
|
16
|
+
* the agent's shell command into it. Returns one disposable tearing down every
|
|
17
|
+
* command, so a settings change can re-register without stale palette entries.
|
|
18
|
+
* `agentSessions`, when given, launch-tags each session for the terminals panel.
|
|
30
19
|
*/
|
|
31
20
|
export function registerAgentCommands(
|
|
32
21
|
app: JupyterFrontEnd,
|
|
@@ -48,9 +37,7 @@ export function registerAgentCommands(
|
|
|
48
37
|
cwd,
|
|
49
38
|
invocation,
|
|
50
39
|
label: agent.label,
|
|
51
|
-
//
|
|
52
|
-
// panel can show its logo right away; server-side detection takes
|
|
53
|
-
// over as the source of truth on its next poll.
|
|
40
|
+
// Optimistic tag; server-side detection takes over on its next poll.
|
|
54
41
|
onSession: name => agentSessions?.set(name, agent.command)
|
|
55
42
|
});
|
|
56
43
|
}
|
|
@@ -62,29 +49,15 @@ export function registerAgentCommands(
|
|
|
62
49
|
|
|
63
50
|
/**
|
|
64
51
|
* Open a fresh terminal, type `invocation` into it as if the user had, and
|
|
65
|
-
* label the tab.
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* `onSession`, when given, is called once with the new session's name right
|
|
70
|
-
* after the terminal is revealed. Callers use it to optimistically tag the
|
|
71
|
-
* session so the terminals panel can badge it with the agent's (or editor's)
|
|
72
|
-
* logo before server-side detection confirms the running process.
|
|
73
|
-
*
|
|
74
|
-
* Resolves with the host `MainAreaWidget` so the caller can place it — the
|
|
75
|
-
* launcher swaps it into its own tab.
|
|
52
|
+
* label the tab. `onSession` receives the new session's name so callers can
|
|
53
|
+
* launch-tag it for the terminals panel. Resolves with the host
|
|
54
|
+
* `MainAreaWidget` so the caller can place it.
|
|
76
55
|
*/
|
|
77
56
|
export async function launchInTerminal(
|
|
78
57
|
commands: CommandRegistry,
|
|
79
58
|
options: {
|
|
80
59
|
cwd?: string;
|
|
81
|
-
/**
|
|
82
|
-
* The literal command line typed into the fresh terminal.
|
|
83
|
-
*/
|
|
84
60
|
invocation: string;
|
|
85
|
-
/**
|
|
86
|
-
* Tab/title label applied once the command is sent.
|
|
87
|
-
*/
|
|
88
61
|
label: string;
|
|
89
62
|
onSession?: (sessionName: string) => void;
|
|
90
63
|
}
|
|
@@ -93,10 +66,8 @@ export async function launchInTerminal(
|
|
|
93
66
|
const main = (await commands.execute('terminal:create-new', {
|
|
94
67
|
cwd
|
|
95
68
|
})) as MainAreaWidget<ITerminal.ITerminal>;
|
|
96
|
-
// `
|
|
97
|
-
//
|
|
98
|
-
// awaiting it guarantees the Terminal widget has finished its constructor
|
|
99
|
-
// and connected its session listeners.
|
|
69
|
+
// `revealed` chains off the terminal's `ready` promise, so awaiting it
|
|
70
|
+
// guarantees the widget finished construction and connected its listeners.
|
|
100
71
|
await main.revealed;
|
|
101
72
|
|
|
102
73
|
const session = main.content.session;
|
|
@@ -114,21 +85,13 @@ export async function launchInTerminal(
|
|
|
114
85
|
type: 'stdin',
|
|
115
86
|
content: [invocation + '\r']
|
|
116
87
|
});
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
// `Terminal {N}` when the WebSocket first reports `connected`; we connect
|
|
120
|
-
// *after* that listener (and call `applyLabel` after `sendCommand`), so by
|
|
121
|
-
// the time we run the upstream listener has already had its turn. Programs
|
|
122
|
-
// that publish a real xterm title escape sequence still win —
|
|
123
|
-
// `XTerm.onTitleChange` resets the label whenever it fires.
|
|
88
|
+
// XTerm's `_initialConnection` resets the title on first connect; we run
|
|
89
|
+
// after it, so this label survives. A title escape still wins (`onTitleChange`).
|
|
124
90
|
applyLabel();
|
|
125
91
|
};
|
|
126
92
|
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
// `connectionStatusChanged` that flips it to `connected`. Without this the
|
|
130
|
-
// stdin write races the websocket handshake and the command silently
|
|
131
|
-
// disappears.
|
|
93
|
+
// Without waiting for `connected` the stdin write races the websocket
|
|
94
|
+
// handshake and the command silently disappears.
|
|
132
95
|
if (session.connectionStatus === 'connected') {
|
|
133
96
|
sendCommand();
|
|
134
97
|
} else {
|
|
@@ -33,46 +33,40 @@ import type { IEditor } from './editors';
|
|
|
33
33
|
import { agentCommandId } from './tokens';
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* shell placement the stock JupyterLab launcher does (swap the launcher
|
|
39
|
-
* tab for the freshly created terminal). Keeping it as an opaque
|
|
40
|
-
* callback means the widget itself does not import `app.shell`.
|
|
36
|
+
* Construction options for the launcher dashboard. `onAgentLaunch` is an
|
|
37
|
+
* opaque callback so the widget itself never imports `app.shell`.
|
|
41
38
|
*/
|
|
42
39
|
interface ILauncherDashboardOptions {
|
|
40
|
+
/**
|
|
41
|
+
* The application command registry, used to launch terminals and run git
|
|
42
|
+
* commands.
|
|
43
|
+
*/
|
|
43
44
|
commands: CommandRegistry;
|
|
44
45
|
/**
|
|
45
|
-
*
|
|
46
|
-
* rank; the widget renders them as-is.
|
|
46
|
+
* Agent list to render, already filtered by availability and sorted by rank.
|
|
47
47
|
*/
|
|
48
48
|
agents: IAgent[];
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
51
|
-
* Vim), or `null` when neither is installed. Resolved by the plugin from the
|
|
52
|
-
* same availability probe that filters the agents.
|
|
50
|
+
* Terminal editor for the "Open" section, or `null` when none is installed.
|
|
53
51
|
*/
|
|
54
52
|
editor: IEditor | null;
|
|
55
53
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* away, the same as agent launches do. `null` when the provider plugin is
|
|
59
|
-
* unavailable.
|
|
54
|
+
* Launch-tag registry so the terminals panel badges editor launches right
|
|
55
|
+
* away; `null` when the provider plugin is unavailable.
|
|
60
56
|
*/
|
|
61
57
|
agentSessions: IAgentSessions | null;
|
|
62
58
|
/**
|
|
63
|
-
* Called
|
|
64
|
-
* plugin uses this to swap the new terminal into the launcher's tab.
|
|
59
|
+
* Called with the launched widget; the plugin swaps it into the launcher's tab.
|
|
65
60
|
*/
|
|
66
61
|
onAgentLaunch: (item: Widget) => void;
|
|
67
62
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* enclosing repo" — same convention as the git panel.
|
|
63
|
+
* Repo path for the changes section. Empty string lets git resolve the
|
|
64
|
+
* enclosing repo from the server root — same convention as the git panel.
|
|
71
65
|
*/
|
|
72
66
|
repoPath: string;
|
|
73
67
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
68
|
+
* Cwd forwarded to `terminal:create-new`. Empty string defaults to the
|
|
69
|
+
* server root.
|
|
76
70
|
*/
|
|
77
71
|
cwd: string;
|
|
78
72
|
/**
|
|
@@ -83,9 +77,7 @@ interface ILauncherDashboardOptions {
|
|
|
83
77
|
}
|
|
84
78
|
|
|
85
79
|
/**
|
|
86
|
-
* Lumino host for the React-based launcher dashboard.
|
|
87
|
-
* `ReactWidget` pattern used by the git panel so the rest of the plugin
|
|
88
|
-
* (layout placement, signals, lifecycle) stays consistent.
|
|
80
|
+
* Lumino host for the React-based launcher dashboard.
|
|
89
81
|
*/
|
|
90
82
|
export class LauncherDashboard extends ReactWidget {
|
|
91
83
|
constructor(options: ILauncherDashboardOptions) {
|
|
@@ -94,6 +86,9 @@ export class LauncherDashboard extends ReactWidget {
|
|
|
94
86
|
this._options = options;
|
|
95
87
|
}
|
|
96
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Render the launcher dashboard component.
|
|
91
|
+
*/
|
|
97
92
|
protected render(): React.ReactElement {
|
|
98
93
|
return <LauncherDashboardComponent {...this._options} />;
|
|
99
94
|
}
|
|
@@ -101,24 +96,31 @@ export class LauncherDashboard extends ReactWidget {
|
|
|
101
96
|
private _options: ILauncherDashboardOptions;
|
|
102
97
|
}
|
|
103
98
|
|
|
99
|
+
/**
|
|
100
|
+
* State of the changes-section git status fetch.
|
|
101
|
+
*/
|
|
104
102
|
interface IGitState {
|
|
103
|
+
/**
|
|
104
|
+
* Whether the initial status fetch is still pending.
|
|
105
|
+
*/
|
|
105
106
|
loading: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* The latest status result, or `null` before the first success or after a
|
|
109
|
+
* failure.
|
|
110
|
+
*/
|
|
106
111
|
result: IGitStatusResult | null;
|
|
112
|
+
/**
|
|
113
|
+
* The latest fetch error message, or `null` when the last fetch succeeded.
|
|
114
|
+
*/
|
|
107
115
|
error: string | null;
|
|
108
116
|
}
|
|
109
117
|
|
|
110
118
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* only opened intentionally, and the grid does not need to be live.
|
|
119
|
+
* Changes-list refresh interval; slower than the git panel since the launcher
|
|
120
|
+
* tab is only opened intentionally.
|
|
114
121
|
*/
|
|
115
122
|
const CHANGES_POLL_INTERVAL_MS = 8000;
|
|
116
123
|
|
|
117
|
-
/**
|
|
118
|
-
* Upper bound on the exponential backoff when the status request fails
|
|
119
|
-
* repeatedly. Matches the rest of the plugin's polls so behavior is
|
|
120
|
-
* consistent across the dashboard, the git panel, and the file tree.
|
|
121
|
-
*/
|
|
122
124
|
const CHANGES_POLL_MAX_MS = 300_000;
|
|
123
125
|
|
|
124
126
|
function LauncherDashboardComponent(
|
|
@@ -154,9 +156,6 @@ function LauncherDashboardComponent(
|
|
|
154
156
|
}
|
|
155
157
|
}, [repoPath]);
|
|
156
158
|
|
|
157
|
-
// Driven by a Lumino `Poll` so the dashboard stops hitting the git
|
|
158
|
-
// endpoint while the JupyterLab tab is hidden, and so repeated
|
|
159
|
-
// failures back off exponentially instead of pegging the 8s cadence.
|
|
160
159
|
React.useEffect(() => {
|
|
161
160
|
const poll = new Poll({
|
|
162
161
|
name: '@xtralab/launcher:gitChanges',
|
|
@@ -201,12 +200,8 @@ function LauncherDashboardComponent(
|
|
|
201
200
|
}, [commands, cwd, onAgentLaunch]);
|
|
202
201
|
|
|
203
202
|
const launchNotebook = React.useCallback(async () => {
|
|
204
|
-
//
|
|
205
|
-
//
|
|
206
|
-
// routes through that dialog when no kernelName is given, so drive the
|
|
207
|
-
// underlying docmanager steps directly and pass `shouldStart: false` to
|
|
208
|
-
// suppress kernel selection. The user picks a kernel from the notebook
|
|
209
|
-
// toolbar when they're ready.
|
|
203
|
+
// `notebook:create-new` always opens the Select Kernel dialog when no
|
|
204
|
+
// kernelName is given, so drive docmanager directly with `shouldStart: false`.
|
|
210
205
|
const file = (await commands.execute('docmanager:new-untitled', {
|
|
211
206
|
path: cwd,
|
|
212
207
|
type: 'notebook'
|
|
@@ -220,8 +215,7 @@ function LauncherDashboardComponent(
|
|
|
220
215
|
kernelPreference: { shouldStart: false, canStart: true }
|
|
221
216
|
})) as IDocumentWidget | undefined;
|
|
222
217
|
if (result) {
|
|
223
|
-
// Match `notebook:create-new`'s
|
|
224
|
-
// save offers a rename instead of overwriting the auto-generated name.
|
|
218
|
+
// Match `notebook:create-new`'s marker so the first save offers a rename.
|
|
225
219
|
result.isUntitled = true;
|
|
226
220
|
onAgentLaunch(result);
|
|
227
221
|
}
|
|
@@ -240,10 +234,6 @@ function LauncherDashboardComponent(
|
|
|
240
234
|
if (!editor) {
|
|
241
235
|
return;
|
|
242
236
|
}
|
|
243
|
-
// An editor is "open a terminal and type its command" — the agent launch
|
|
244
|
-
// minus the prompt — so it shares `launchInTerminal` rather than the native
|
|
245
|
-
// `terminal:create-new` call the tiles above use, and tags the session the
|
|
246
|
-
// same way so the terminals panel badges it with the editor's logo.
|
|
247
237
|
const result = await launchInTerminal(commands, {
|
|
248
238
|
cwd,
|
|
249
239
|
invocation: editor.command,
|
|
@@ -301,10 +291,6 @@ function ChangesSection(props: {
|
|
|
301
291
|
const { git, onOpen, onRefresh, trans } = props;
|
|
302
292
|
const files = git.result ? expandStatusFiles(git.result.files) : [];
|
|
303
293
|
|
|
304
|
-
// Native `<details>` rather than a hand-rolled toggle: we get the
|
|
305
|
-
// disclosure triangle, keyboard handling, and aria-expanded semantics
|
|
306
|
-
// for free, and the user's open/closed choice is tab-local state that
|
|
307
|
-
// we don't need to persist.
|
|
308
294
|
return (
|
|
309
295
|
<details
|
|
310
296
|
className="jp-xtralab-Launcher-section jp-xtralab-Launcher-changes-section"
|
|
@@ -330,8 +316,7 @@ function ChangesSection(props: {
|
|
|
330
316
|
type="button"
|
|
331
317
|
className="jp-xtralab-Launcher-section-action"
|
|
332
318
|
aria-label={trans.__('Refresh changes')}
|
|
333
|
-
//
|
|
334
|
-
// refreshing while the section is open shouldn't collapse it.
|
|
319
|
+
// Keep the click from toggling the surrounding `<details>`.
|
|
335
320
|
onClick={event => {
|
|
336
321
|
event.preventDefault();
|
|
337
322
|
event.stopPropagation();
|
|
@@ -417,9 +402,6 @@ function AgentSection(props: {
|
|
|
417
402
|
const { agents, prompt, onPromptChange, onLaunch, trans } = props;
|
|
418
403
|
const trimmed = prompt.trim();
|
|
419
404
|
const promptActive = trimmed.length > 0;
|
|
420
|
-
// The first prompt-capable agent is what Cmd/Ctrl+Enter fires; the hint
|
|
421
|
-
// text below the textarea names it so the keyboard shortcut target
|
|
422
|
-
// isn't a mystery.
|
|
423
405
|
const primaryAgent = agents.find(agent => agent.promptArgs !== undefined);
|
|
424
406
|
const hintId = 'jp-xtralab-Launcher-agent-hint';
|
|
425
407
|
|
|
@@ -501,24 +483,17 @@ function AgentSection(props: {
|
|
|
501
483
|
}
|
|
502
484
|
|
|
503
485
|
/**
|
|
504
|
-
*
|
|
505
|
-
*
|
|
506
|
-
* Vibe, Antigravity) register MCP through their own config files or UI, so
|
|
507
|
-
* there is no one-line command to surface for them.
|
|
486
|
+
* Agents whose CLI has a non-interactive `mcp add <name> -- <command>`; the
|
|
487
|
+
* other agents register MCP through their own config, so no one-liner exists.
|
|
508
488
|
*/
|
|
509
489
|
const MCP_ADD_AGENT_IDS = new Set(['claude', 'codex', 'copilot']);
|
|
510
490
|
|
|
511
|
-
/**
|
|
512
|
-
* The stdio proxy console script that bridges an agent to the MCP server.
|
|
513
|
-
*/
|
|
514
491
|
const MCP_PROXY_COMMAND = 'jupyter-server-mcp-proxy';
|
|
515
492
|
|
|
516
493
|
/**
|
|
517
|
-
* Copy
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
* (the desktop app's Electron window can deny clipboard writes by policy).
|
|
521
|
-
* Returns whether the copy succeeded.
|
|
494
|
+
* Copy via a hidden `<textarea>` and the legacy `execCommand('copy')`:
|
|
495
|
+
* deprecated, but the reliable fallback when the async Clipboard API is
|
|
496
|
+
* missing or blocked (Electron can deny it by policy). Returns success.
|
|
522
497
|
*/
|
|
523
498
|
function legacyCopy(text: string): boolean {
|
|
524
499
|
try {
|
|
@@ -539,13 +514,10 @@ function legacyCopy(text: string): boolean {
|
|
|
539
514
|
}
|
|
540
515
|
|
|
541
516
|
/**
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
* supervisor exports `JUPYTER_SERVER_MCP_URL`, and `pip` installs let the
|
|
547
|
-
* proxy discover the server from its runtime file. Renders nothing when none
|
|
548
|
-
* of those agents are on `$PATH`.
|
|
517
|
+
* Collapsed-by-default hint listing the `mcp add` one-liner per installed
|
|
518
|
+
* agent. Copy-only: run in the user's own terminal, where the proxy finds the
|
|
519
|
+
* server with no port (desktop exports `JUPYTER_SERVER_MCP_URL`; pip installs
|
|
520
|
+
* discover it from the runtime file). Renders nothing when no agent qualifies.
|
|
549
521
|
*/
|
|
550
522
|
function McpSection(props: {
|
|
551
523
|
agents: IAgent[];
|
|
@@ -569,9 +541,6 @@ function McpSection(props: {
|
|
|
569
541
|
};
|
|
570
542
|
|
|
571
543
|
const copy = (command: string, id: string): void => {
|
|
572
|
-
// Prefer the async Clipboard API; fall back to `legacyCopy` when it's
|
|
573
|
-
// missing or rejects (Electron can block it by policy). Flag "Copied" only
|
|
574
|
-
// once a copy actually succeeds.
|
|
575
544
|
const clipboard = navigator.clipboard;
|
|
576
545
|
if (clipboard) {
|
|
577
546
|
void clipboard.writeText(command).then(
|
|
@@ -638,16 +607,8 @@ function McpSection(props: {
|
|
|
638
607
|
}
|
|
639
608
|
|
|
640
609
|
/**
|
|
641
|
-
* The non-agent launch tiles
|
|
642
|
-
*
|
|
643
|
-
* they don't compete with the AI agents visually, and they're always
|
|
644
|
-
* available regardless of the agent prompt textarea (which doesn't
|
|
645
|
-
* apply to them).
|
|
646
|
-
*
|
|
647
|
-
* A terminal editor (Neovim, else Vim) joins the row when one is installed —
|
|
648
|
-
* it opens in a terminal like the agents do, so it lives here rather than in
|
|
649
|
-
* the agent grid. When neither is on `$PATH`, `editor` is `null` and no tile
|
|
650
|
-
* renders.
|
|
610
|
+
* The non-agent launch tiles: terminal, notebook, and console, plus the
|
|
611
|
+
* terminal editor tile when one is installed (`editor` is `null` otherwise).
|
|
651
612
|
*/
|
|
652
613
|
function OpenSection(props: {
|
|
653
614
|
editor: IEditor | null;
|
|
@@ -19,37 +19,28 @@ import {
|
|
|
19
19
|
} from './schemaDefaults';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* A read-only, observable view of the launcher's terminal editors:
|
|
23
|
-
* built-ins
|
|
24
|
-
* rank, with disabled entries removed.
|
|
22
|
+
* A read-only, observable view of the launcher's terminal editors: the
|
|
23
|
+
* built-ins merged with the user's `editors` setting.
|
|
25
24
|
*/
|
|
26
25
|
export interface IEditorRegistry {
|
|
27
26
|
/**
|
|
28
|
-
* The
|
|
29
|
-
*
|
|
30
|
-
* running, and to tell the server which editor commands to detect.
|
|
27
|
+
* The merged editor list (disabled entries removed); the terminals panel
|
|
28
|
+
* uses it to badge running editors.
|
|
31
29
|
*/
|
|
32
30
|
readonly editors: IEditor[];
|
|
33
31
|
|
|
34
32
|
/**
|
|
35
|
-
* The single
|
|
36
|
-
*
|
|
37
|
-
* qualifies.
|
|
33
|
+
* The single launcher tile: the first editor, by rank, whose command is on
|
|
34
|
+
* `$PATH`, or `null` when none qualifies.
|
|
38
35
|
*/
|
|
39
36
|
readonly current: IEditor | null;
|
|
40
37
|
|
|
41
38
|
/**
|
|
42
|
-
* Emitted whenever {@link editors} or {@link current} changes
|
|
43
|
-
* edited the `editors` setting). Consumers that read on demand can ignore it.
|
|
39
|
+
* Emitted whenever {@link editors} or {@link current} changes.
|
|
44
40
|
*/
|
|
45
41
|
readonly changed: ISignal<IEditorRegistry, void>;
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
/**
|
|
49
|
-
* DI token for {@link IEditorRegistry}. Provided by `xtralab:editor-registry`
|
|
50
|
-
* and consumed — optionally — by `xtralab:launcher` (for its tile) and
|
|
51
|
-
* `xtralab:terminals` (to badge running editors with their logo).
|
|
52
|
-
*/
|
|
53
44
|
export const IEditorRegistry = new Token<IEditorRegistry>(
|
|
54
45
|
'xtralab:IEditorRegistry',
|
|
55
46
|
'A read-only, observable view of the launcher terminal editors, shared so the launcher tile and the terminals panel agree on the list and icons.'
|
|
@@ -57,23 +48,32 @@ export const IEditorRegistry = new Token<IEditorRegistry>(
|
|
|
57
48
|
|
|
58
49
|
/**
|
|
59
50
|
* Concrete {@link IEditorRegistry}. The provider plugin is the only writer, so
|
|
60
|
-
*
|
|
51
|
+
* {@link set} is kept off the shared token.
|
|
61
52
|
*/
|
|
62
53
|
class EditorRegistry implements IEditorRegistry {
|
|
54
|
+
/**
|
|
55
|
+
* The merged editor list (disabled entries removed).
|
|
56
|
+
*/
|
|
63
57
|
get editors(): IEditor[] {
|
|
64
58
|
return this._editors;
|
|
65
59
|
}
|
|
66
60
|
|
|
61
|
+
/**
|
|
62
|
+
* The launcher-tile editor, or `null` when none qualifies.
|
|
63
|
+
*/
|
|
67
64
|
get current(): IEditor | null {
|
|
68
65
|
return this._current;
|
|
69
66
|
}
|
|
70
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Emitted whenever {@link editors} or {@link current} changes.
|
|
70
|
+
*/
|
|
71
71
|
get changed(): ISignal<IEditorRegistry, void> {
|
|
72
72
|
return this._changed;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* Replace both lists
|
|
76
|
+
* Replace both lists and notify observers.
|
|
77
77
|
*/
|
|
78
78
|
set(editors: IEditor[], current: IEditor | null): void {
|
|
79
79
|
this._editors = editors;
|
|
@@ -87,12 +87,9 @@ class EditorRegistry implements IEditorRegistry {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* Provides {@link IEditorRegistry}: merges
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* `activate` awaits the first probe before returning, so a consumer reading
|
|
95
|
-
* {@link IEditorRegistry.current} on activation sees a resolved tile.
|
|
90
|
+
* Provides {@link IEditorRegistry}: merges the built-in editors with the
|
|
91
|
+
* `editors` setting and probes the server's `$PATH`. `activate` awaits the
|
|
92
|
+
* first probe, so consumers see a resolved tile on activation.
|
|
96
93
|
*/
|
|
97
94
|
export const editorRegistryPlugin: JupyterFrontEndPlugin<IEditorRegistry> = {
|
|
98
95
|
id: 'xtralab:editor-registry',
|
|
@@ -109,9 +106,6 @@ export const editorRegistryPlugin: JupyterFrontEndPlugin<IEditorRegistry> = {
|
|
|
109
106
|
|
|
110
107
|
const apply = async (overrides: IEditorSettings[]): Promise<void> => {
|
|
111
108
|
const editors = mergeEditors(overrides);
|
|
112
|
-
// Probe only the editors that opt into the availability check; entries
|
|
113
|
-
// with `requireAvailable: false` (e.g. a shell alias) are shown
|
|
114
|
-
// regardless and don't need a `which` lookup.
|
|
115
109
|
const probe = Array.from(
|
|
116
110
|
new Set(
|
|
117
111
|
editors
|
|
@@ -146,8 +140,6 @@ export const editorRegistryPlugin: JupyterFrontEndPlugin<IEditorRegistry> = {
|
|
|
146
140
|
});
|
|
147
141
|
} catch (reason) {
|
|
148
142
|
console.error('xtralab: failed to load editor settings', reason);
|
|
149
|
-
// Settings load failed — fall back to the built-in editors so the
|
|
150
|
-
// launcher tile still resolves instead of going silent.
|
|
151
143
|
await apply([]);
|
|
152
144
|
}
|
|
153
145
|
} else {
|