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.
Files changed (237) hide show
  1. package/README.md +65 -30
  2. package/lib/about/icons.d.ts +0 -5
  3. package/lib/about/icons.js +0 -5
  4. package/lib/about/index.d.ts +4 -8
  5. package/lib/about/index.js +6 -17
  6. package/lib/agentSessions.d.ts +9 -29
  7. package/lib/agentSessions.js +2 -7
  8. package/lib/askAgent/editorSelection.d.ts +20 -26
  9. package/lib/askAgent/editorSelection.js +11 -26
  10. package/lib/askAgent/icons.d.ts +2 -3
  11. package/lib/askAgent/icons.js +2 -3
  12. package/lib/askAgent/index.d.ts +4 -26
  13. package/lib/askAgent/index.js +54 -158
  14. package/lib/askAgent/popup.d.ts +12 -16
  15. package/lib/askAgent/popup.js +18 -37
  16. package/lib/askAgent/prompt.d.ts +3 -5
  17. package/lib/askAgent/prompt.js +6 -19
  18. package/lib/askAgent/queue.d.ts +11 -21
  19. package/lib/askAgent/queue.js +9 -19
  20. package/lib/askAgent/queuePanel.d.ts +13 -18
  21. package/lib/askAgent/queuePanel.js +15 -37
  22. package/lib/askAgent/targetPicker.d.ts +2 -9
  23. package/lib/askAgent/targetPicker.js +6 -11
  24. package/lib/askAgent/tokens.d.ts +32 -46
  25. package/lib/askAgent/tokens.js +4 -6
  26. package/lib/commandBar/index.d.ts +4 -13
  27. package/lib/commandBar/index.js +21 -39
  28. package/lib/customPanel/index.js +15 -0
  29. package/lib/editorBreadcrumbs/index.d.ts +3 -6
  30. package/lib/editorBreadcrumbs/index.js +10 -6
  31. package/lib/editorBreadcrumbs/widget.d.ts +17 -4
  32. package/lib/editorBreadcrumbs/widget.js +11 -17
  33. package/lib/editorIndent/index.d.ts +4 -12
  34. package/lib/editorIndent/index.js +8 -23
  35. package/lib/fileBrowser/commands.d.ts +29 -19
  36. package/lib/fileBrowser/commands.js +83 -97
  37. package/lib/fileBrowser/contents.d.ts +3 -0
  38. package/lib/fileBrowser/dragAndDrop.d.ts +17 -4
  39. package/lib/fileBrowser/dragAndDrop.js +2 -7
  40. package/lib/fileBrowser/fileBrowser.d.ts +19 -9
  41. package/lib/fileBrowser/fileBrowser.js +70 -222
  42. package/lib/fileBrowser/gitStatus.d.ts +16 -10
  43. package/lib/fileBrowser/gitStatus.js +31 -30
  44. package/lib/fileBrowser/gitignore.d.ts +4 -17
  45. package/lib/fileBrowser/gitignore.js +4 -25
  46. package/lib/fileBrowser/icons.d.ts +7 -17
  47. package/lib/fileBrowser/icons.js +25 -80
  48. package/lib/fileBrowser/index.js +2 -4
  49. package/lib/fileBrowser/widget.d.ts +141 -48
  50. package/lib/fileBrowser/widget.js +102 -4
  51. package/lib/fileTypeIcons/index.js +0 -10
  52. package/lib/git/api.d.ts +5 -13
  53. package/lib/git/api.js +10 -36
  54. package/lib/git/askRequest.d.ts +4 -8
  55. package/lib/git/askRequest.js +6 -20
  56. package/lib/git/commands.d.ts +45 -5
  57. package/lib/git/commands.js +20 -13
  58. package/lib/git/diffModel.js +4 -0
  59. package/lib/git/diffPreferences.d.ts +90 -0
  60. package/lib/git/diffPreferences.js +107 -0
  61. package/lib/git/diffProvider.js +10 -2
  62. package/lib/git/diffSurface.d.ts +64 -63
  63. package/lib/git/diffSurface.js +72 -213
  64. package/lib/git/diffTheme.d.ts +7 -0
  65. package/lib/git/diffTheme.js +23 -0
  66. package/lib/git/diffWidget.d.ts +70 -14
  67. package/lib/git/diffWidget.js +100 -94
  68. package/lib/git/imageDiff.d.ts +14 -6
  69. package/lib/git/imageDiff.js +19 -75
  70. package/lib/git/index.d.ts +0 -3
  71. package/lib/git/index.js +44 -10
  72. package/lib/git/notebookDiff.d.ts +110 -33
  73. package/lib/git/notebookDiff.js +55 -197
  74. package/lib/git/tokens.d.ts +73 -31
  75. package/lib/git/tokens.js +2 -3
  76. package/lib/highlight/index.d.ts +4 -10
  77. package/lib/highlight/index.js +10 -41
  78. package/lib/index.d.ts +0 -9
  79. package/lib/index.js +0 -9
  80. package/lib/launcher/agents.d.ts +55 -51
  81. package/lib/launcher/agents.js +15 -57
  82. package/lib/launcher/availability.d.ts +3 -9
  83. package/lib/launcher/availability.js +3 -9
  84. package/lib/launcher/commands.d.ts +7 -32
  85. package/lib/launcher/commands.js +14 -45
  86. package/lib/launcher/dashboard.d.ts +19 -24
  87. package/lib/launcher/dashboard.js +21 -67
  88. package/lib/launcher/editorRegistry.d.ts +10 -22
  89. package/lib/launcher/editorRegistry.js +14 -18
  90. package/lib/launcher/editors.d.ts +39 -45
  91. package/lib/launcher/editors.js +8 -34
  92. package/lib/launcher/icons.d.ts +0 -12
  93. package/lib/launcher/icons.js +5 -39
  94. package/lib/launcher/index.js +12 -55
  95. package/lib/launcher/invocation.d.ts +4 -10
  96. package/lib/launcher/invocation.js +7 -22
  97. package/lib/launcher/registry.d.ts +9 -7
  98. package/lib/launcher/registry.js +9 -7
  99. package/lib/launcher/tokens.d.ts +10 -22
  100. package/lib/launcher/tokens.js +5 -8
  101. package/lib/menuBar/index.d.ts +3 -10
  102. package/lib/menuBar/index.js +11 -28
  103. package/lib/menus/index.d.ts +3 -9
  104. package/lib/menus/index.js +14 -30
  105. package/lib/omnibox/files.d.ts +2 -4
  106. package/lib/omnibox/files.js +5 -11
  107. package/lib/omnibox/index.d.ts +4 -14
  108. package/lib/omnibox/index.js +9 -27
  109. package/lib/omnibox/model.d.ts +38 -10
  110. package/lib/omnibox/model.js +15 -33
  111. package/lib/omnibox/recents.d.ts +15 -17
  112. package/lib/omnibox/recents.js +12 -17
  113. package/lib/omnibox/tokens.d.ts +5 -10
  114. package/lib/omnibox/tokens.js +2 -6
  115. package/lib/omnibox/widget.d.ts +11 -7
  116. package/lib/omnibox/widget.js +8 -16
  117. package/lib/searchReplace/index.d.ts +4 -20
  118. package/lib/searchReplace/index.js +7 -27
  119. package/lib/showOutput/index.d.ts +3 -12
  120. package/lib/showOutput/index.js +6 -22
  121. package/lib/sidebar/index.d.ts +4 -7
  122. package/lib/sidebar/index.js +5 -12
  123. package/lib/terminalNotifications/index.d.ts +4 -10
  124. package/lib/terminalNotifications/index.js +6 -20
  125. package/lib/terminals/agentTerminals.d.ts +12 -5
  126. package/lib/terminals/agentTerminals.js +25 -44
  127. package/lib/terminals/detection.d.ts +4 -8
  128. package/lib/terminals/detection.js +4 -8
  129. package/lib/terminals/index.d.ts +0 -35
  130. package/lib/terminals/index.js +12 -101
  131. package/lib/terminals/model.d.ts +64 -139
  132. package/lib/terminals/model.js +80 -220
  133. package/lib/terminals/tokens.d.ts +11 -22
  134. package/lib/terminals/tokens.js +2 -2
  135. package/lib/terminals/widget.d.ts +43 -13
  136. package/lib/terminals/widget.js +33 -18
  137. package/lib/topBar/icons.d.ts +3 -8
  138. package/lib/topBar/icons.js +3 -8
  139. package/lib/topBar/index.d.ts +4 -11
  140. package/lib/topBar/index.js +10 -38
  141. package/lib/walkthrough/index.d.ts +4 -9
  142. package/lib/walkthrough/index.js +6 -20
  143. package/lib/walkthrough/panel.d.ts +40 -9
  144. package/lib/walkthrough/panel.js +4 -10
  145. package/package.json +5 -3
  146. package/schema/git-diff-preferences.json +42 -0
  147. package/src/about/icons.ts +0 -5
  148. package/src/about/index.tsx +6 -17
  149. package/src/agentSessions.ts +9 -29
  150. package/src/askAgent/editorSelection.ts +22 -29
  151. package/src/askAgent/icons.ts +2 -3
  152. package/src/askAgent/index.ts +54 -158
  153. package/src/askAgent/popup.tsx +23 -45
  154. package/src/askAgent/prompt.ts +6 -19
  155. package/src/askAgent/queue.ts +13 -24
  156. package/src/askAgent/queuePanel.tsx +21 -46
  157. package/src/askAgent/targetPicker.tsx +5 -15
  158. package/src/askAgent/tokens.ts +32 -46
  159. package/src/commandBar/index.ts +24 -39
  160. package/src/customPanel/index.ts +15 -0
  161. package/src/editorBreadcrumbs/index.ts +10 -6
  162. package/src/editorBreadcrumbs/widget.ts +23 -17
  163. package/src/editorIndent/index.ts +17 -23
  164. package/src/fileBrowser/commands.ts +119 -96
  165. package/src/fileBrowser/contents.ts +3 -0
  166. package/src/fileBrowser/dragAndDrop.ts +17 -7
  167. package/src/fileBrowser/fileBrowser.tsx +86 -230
  168. package/src/fileBrowser/gitStatus.ts +36 -33
  169. package/src/fileBrowser/gitignore.ts +4 -25
  170. package/src/fileBrowser/icons.ts +25 -80
  171. package/src/fileBrowser/index.ts +2 -4
  172. package/src/fileBrowser/widget.tsx +171 -50
  173. package/src/fileTypeIcons/index.ts +0 -10
  174. package/src/git/api.ts +10 -36
  175. package/src/git/askRequest.ts +6 -20
  176. package/src/git/commands.ts +83 -11
  177. package/src/git/diffModel.ts +25 -0
  178. package/src/git/diffPreferences.ts +192 -0
  179. package/src/git/diffProvider.tsx +11 -2
  180. package/src/git/diffSurface.tsx +165 -286
  181. package/src/git/diffTheme.ts +24 -0
  182. package/src/git/diffWidget.tsx +194 -134
  183. package/src/git/imageDiff.tsx +56 -84
  184. package/src/git/index.ts +54 -10
  185. package/src/git/notebookDiff.tsx +214 -240
  186. package/src/git/tokens.ts +73 -31
  187. package/src/highlight/index.ts +10 -41
  188. package/src/index.ts +0 -9
  189. package/src/launcher/agents.ts +64 -95
  190. package/src/launcher/availability.ts +3 -9
  191. package/src/launcher/commands.ts +14 -51
  192. package/src/launcher/dashboard.tsx +49 -88
  193. package/src/launcher/editorRegistry.ts +21 -29
  194. package/src/launcher/editors.ts +39 -58
  195. package/src/launcher/icons.ts +5 -39
  196. package/src/launcher/index.ts +12 -55
  197. package/src/launcher/invocation.ts +7 -22
  198. package/src/launcher/registry.ts +9 -7
  199. package/src/launcher/tokens.ts +10 -22
  200. package/src/menuBar/index.ts +11 -28
  201. package/src/menus/index.ts +14 -30
  202. package/src/omnibox/files.ts +10 -14
  203. package/src/omnibox/index.ts +9 -27
  204. package/src/omnibox/model.ts +50 -38
  205. package/src/omnibox/recents.ts +17 -22
  206. package/src/omnibox/tokens.ts +5 -10
  207. package/src/omnibox/widget.tsx +14 -19
  208. package/src/searchReplace/index.ts +7 -27
  209. package/src/showOutput/index.ts +6 -22
  210. package/src/sidebar/index.ts +20 -12
  211. package/src/terminalNotifications/index.ts +42 -25
  212. package/src/terminals/agentTerminals.ts +25 -49
  213. package/src/terminals/detection.ts +4 -8
  214. package/src/terminals/index.ts +12 -101
  215. package/src/terminals/model.ts +130 -246
  216. package/src/terminals/tokens.ts +11 -22
  217. package/src/terminals/widget.tsx +48 -31
  218. package/src/topBar/icons.ts +3 -8
  219. package/src/topBar/index.ts +21 -44
  220. package/src/walkthrough/index.ts +6 -20
  221. package/src/walkthrough/panel.ts +40 -10
  222. package/style/about.css +2 -7
  223. package/style/askAgent.css +8 -40
  224. package/style/base.css +9 -45
  225. package/style/chrome.css +108 -308
  226. package/style/commandBar.css +4 -20
  227. package/style/customPanel.css +1 -4
  228. package/style/git.css +26 -186
  229. package/style/highlight.css +1 -3
  230. package/style/launcher.css +6 -70
  231. package/style/omnibox.css +2 -14
  232. package/style/showOutput.css +0 -6
  233. package/style/sidebar.css +29 -9
  234. package/style/tabs.css +5 -13
  235. package/style/terminals.css +6 -53
  236. package/style/topBar.css +2 -22
  237. package/style/walkthrough.css +0 -8
@@ -7,46 +7,40 @@ import type { IAgentSessions } from '../agentSessions';
7
7
  import type { IAgent } from './agents';
8
8
  import type { IEditor } from './editors';
9
9
  /**
10
- * Public construction options for the launcher dashboard widget. The
11
- * plugin supplies an `onAgentLaunch` callback that performs the same
12
- * shell placement the stock JupyterLab launcher does (swap the launcher
13
- * tab for the freshly created terminal). Keeping it as an opaque
14
- * callback means the widget itself does not import `app.shell`.
10
+ * Construction options for the launcher dashboard. `onAgentLaunch` is an
11
+ * opaque callback so the widget itself never imports `app.shell`.
15
12
  */
16
13
  interface ILauncherDashboardOptions {
14
+ /**
15
+ * The application command registry, used to launch terminals and run git
16
+ * commands.
17
+ */
17
18
  commands: CommandRegistry;
18
19
  /**
19
- * The agent list to render. Already filtered by availability + sorted by
20
- * rank; the widget renders them as-is.
20
+ * Agent list to render, already filtered by availability and sorted by rank.
21
21
  */
22
22
  agents: IAgent[];
23
23
  /**
24
- * The terminal editor to offer in the "Open" section (Neovim preferred over
25
- * Vim), or `null` when neither is installed. Resolved by the plugin from the
26
- * same availability probe that filters the agents.
24
+ * Terminal editor for the "Open" section, or `null` when none is installed.
27
25
  */
28
26
  editor: IEditor | null;
29
27
  /**
30
- * Shared launch-tag registry. When the editor tile launches, it records the
31
- * session here so the terminals panel badges it with the editor's logo right
32
- * away, the same as agent launches do. `null` when the provider plugin is
33
- * unavailable.
28
+ * Launch-tag registry so the terminals panel badges editor launches right
29
+ * away; `null` when the provider plugin is unavailable.
34
30
  */
35
31
  agentSessions: IAgentSessions | null;
36
32
  /**
37
- * Called after an agent command has returned its top-level widget. The
38
- * plugin uses this to swap the new terminal into the launcher's tab.
33
+ * Called with the launched widget; the plugin swaps it into the launcher's tab.
39
34
  */
40
35
  onAgentLaunch: (item: Widget) => void;
41
36
  /**
42
- * The git server-relative repo path used by the changes section. Empty
43
- * string means "use the JupyterLab server's root and let git resolve the
44
- * enclosing repo" — same convention as the git panel.
37
+ * Repo path for the changes section. Empty string lets git resolve the
38
+ * enclosing repo from the server root — same convention as the git panel.
45
39
  */
46
40
  repoPath: string;
47
41
  /**
48
- * The cwd forwarded to `terminal:create-new` when an agent is launched.
49
- * Empty string lets the terminal extension default to the server root.
42
+ * Cwd forwarded to `terminal:create-new`. Empty string defaults to the
43
+ * server root.
50
44
  */
51
45
  cwd: string;
52
46
  /**
@@ -56,12 +50,13 @@ interface ILauncherDashboardOptions {
56
50
  trans: TranslationBundle;
57
51
  }
58
52
  /**
59
- * Lumino host for the React-based launcher dashboard. Mirrors the
60
- * `ReactWidget` pattern used by the git panel so the rest of the plugin
61
- * (layout placement, signals, lifecycle) stays consistent.
53
+ * Lumino host for the React-based launcher dashboard.
62
54
  */
63
55
  export declare class LauncherDashboard extends ReactWidget {
64
56
  constructor(options: ILauncherDashboardOptions);
57
+ /**
58
+ * Render the launcher dashboard component.
59
+ */
65
60
  protected render(): React.ReactElement;
66
61
  private _options;
67
62
  }
@@ -6,9 +6,7 @@ import { CommandIDs as GitCommandIDs } from '../git/commands';
6
6
  import { launchInTerminal } from './commands';
7
7
  import { agentCommandId } from './tokens';
8
8
  /**
9
- * Lumino host for the React-based launcher dashboard. Mirrors the
10
- * `ReactWidget` pattern used by the git panel so the rest of the plugin
11
- * (layout placement, signals, lifecycle) stays consistent.
9
+ * Lumino host for the React-based launcher dashboard.
12
10
  */
13
11
  export class LauncherDashboard extends ReactWidget {
14
12
  constructor(options) {
@@ -16,21 +14,18 @@ export class LauncherDashboard extends ReactWidget {
16
14
  this.addClass('jp-xtralab-Launcher');
17
15
  this._options = options;
18
16
  }
17
+ /**
18
+ * Render the launcher dashboard component.
19
+ */
19
20
  render() {
20
21
  return React.createElement(LauncherDashboardComponent, { ...this._options });
21
22
  }
22
23
  }
23
24
  /**
24
- * Refresh interval for the changes list. A bit slower than the git panel
25
- * (which sits in the sidebar and is always visible) — the launcher tab is
26
- * only opened intentionally, and the grid does not need to be live.
25
+ * Changes-list refresh interval; slower than the git panel since the launcher
26
+ * tab is only opened intentionally.
27
27
  */
28
28
  const CHANGES_POLL_INTERVAL_MS = 8000;
29
- /**
30
- * Upper bound on the exponential backoff when the status request fails
31
- * repeatedly. Matches the rest of the plugin's polls so behavior is
32
- * consistent across the dashboard, the git panel, and the file tree.
33
- */
34
29
  const CHANGES_POLL_MAX_MS = 300000;
35
30
  function LauncherDashboardComponent(props) {
36
31
  const { commands, agents, editor, agentSessions, onAgentLaunch, repoPath, cwd, trans } = props;
@@ -53,9 +48,6 @@ function LauncherDashboardComponent(props) {
53
48
  });
54
49
  }
55
50
  }, [repoPath]);
56
- // Driven by a Lumino `Poll` so the dashboard stops hitting the git
57
- // endpoint while the JupyterLab tab is hidden, and so repeated
58
- // failures back off exponentially instead of pegging the 8s cadence.
59
51
  React.useEffect(() => {
60
52
  const poll = new Poll({
61
53
  name: '@xtralab/launcher:gitChanges',
@@ -91,12 +83,8 @@ function LauncherDashboardComponent(props) {
91
83
  }
92
84
  }, [commands, cwd, onAgentLaunch]);
93
85
  const launchNotebook = React.useCallback(async () => {
94
- // Open a fresh notebook with no kernel attached — equivalent to clicking
95
- // "No Kernel" in the Select Kernel dialog. `notebook:create-new` always
96
- // routes through that dialog when no kernelName is given, so drive the
97
- // underlying docmanager steps directly and pass `shouldStart: false` to
98
- // suppress kernel selection. The user picks a kernel from the notebook
99
- // toolbar when they're ready.
86
+ // `notebook:create-new` always opens the Select Kernel dialog when no
87
+ // kernelName is given, so drive docmanager directly with `shouldStart: false`.
100
88
  const file = (await commands.execute('docmanager:new-untitled', {
101
89
  path: cwd,
102
90
  type: 'notebook'
@@ -110,8 +98,7 @@ function LauncherDashboardComponent(props) {
110
98
  kernelPreference: { shouldStart: false, canStart: true }
111
99
  }));
112
100
  if (result) {
113
- // Match `notebook:create-new`'s post-open marker so the first manual
114
- // save offers a rename instead of overwriting the auto-generated name.
101
+ // Match `notebook:create-new`'s marker so the first save offers a rename.
115
102
  result.isUntitled = true;
116
103
  onAgentLaunch(result);
117
104
  }
@@ -128,10 +115,6 @@ function LauncherDashboardComponent(props) {
128
115
  if (!editor) {
129
116
  return;
130
117
  }
131
- // An editor is "open a terminal and type its command" — the agent launch
132
- // minus the prompt — so it shares `launchInTerminal` rather than the native
133
- // `terminal:create-new` call the tiles above use, and tags the session the
134
- // same way so the terminals panel badges it with the editor's logo.
135
118
  const result = await launchInTerminal(commands, {
136
119
  cwd,
137
120
  invocation: editor.command,
@@ -153,17 +136,12 @@ function LauncherDashboardComponent(props) {
153
136
  function ChangesSection(props) {
154
137
  const { git, onOpen, onRefresh, trans } = props;
155
138
  const files = git.result ? expandStatusFiles(git.result.files) : [];
156
- // Native `<details>` rather than a hand-rolled toggle: we get the
157
- // disclosure triangle, keyboard handling, and aria-expanded semantics
158
- // for free, and the user's open/closed choice is tab-local state that
159
- // we don't need to persist.
160
139
  return (React.createElement("details", { className: "jp-xtralab-Launcher-section jp-xtralab-Launcher-changes-section", open: true },
161
140
  React.createElement("summary", { className: "jp-xtralab-Launcher-section-summary" },
162
141
  React.createElement("span", { className: "jp-xtralab-Launcher-section-title" }, trans.__('Changes')),
163
142
  files.length > 0 && (React.createElement("span", { className: "jp-xtralab-Launcher-section-count", "aria-label": trans._n('%1 changed file', '%1 changed files', files.length) }, files.length)),
164
143
  React.createElement("button", { type: "button", className: "jp-xtralab-Launcher-section-action", "aria-label": trans.__('Refresh changes'),
165
- // Stop the click from toggling the surrounding `<details>` —
166
- // refreshing while the section is open shouldn't collapse it.
144
+ // Keep the click from toggling the surrounding `<details>`.
167
145
  onClick: event => {
168
146
  event.preventDefault();
169
147
  event.stopPropagation();
@@ -205,9 +183,6 @@ function AgentSection(props) {
205
183
  const { agents, prompt, onPromptChange, onLaunch, trans } = props;
206
184
  const trimmed = prompt.trim();
207
185
  const promptActive = trimmed.length > 0;
208
- // The first prompt-capable agent is what Cmd/Ctrl+Enter fires; the hint
209
- // text below the textarea names it so the keyboard shortcut target
210
- // isn't a mystery.
211
186
  const primaryAgent = agents.find(agent => agent.promptArgs !== undefined);
212
187
  const hintId = 'jp-xtralab-Launcher-agent-hint';
213
188
  return (React.createElement("section", { className: "jp-xtralab-Launcher-section" },
@@ -236,22 +211,15 @@ function AgentSection(props) {
236
211
  }))));
237
212
  }
238
213
  /**
239
- * Launcher agents whose CLI has a clean, non-interactive `mcp add` that takes
240
- * `<name> -- <command>`. The other agents (Goose, OpenCode, Kiro, Mistral
241
- * Vibe, Antigravity) register MCP through their own config files or UI, so
242
- * there is no one-line command to surface for them.
214
+ * Agents whose CLI has a non-interactive `mcp add <name> -- <command>`; the
215
+ * other agents register MCP through their own config, so no one-liner exists.
243
216
  */
244
217
  const MCP_ADD_AGENT_IDS = new Set(['claude', 'codex', 'copilot']);
245
- /**
246
- * The stdio proxy console script that bridges an agent to the MCP server.
247
- */
248
218
  const MCP_PROXY_COMMAND = 'jupyter-server-mcp-proxy';
249
219
  /**
250
- * Copy `text` to the clipboard via a hidden, selected `<textarea>` and the
251
- * legacy `execCommand('copy')`. Deprecated, but still the most reliable path
252
- * under a user gesture when the async Clipboard API is unavailable or blocked
253
- * (the desktop app's Electron window can deny clipboard writes by policy).
254
- * Returns whether the copy succeeded.
220
+ * Copy via a hidden `<textarea>` and the legacy `execCommand('copy')`:
221
+ * deprecated, but the reliable fallback when the async Clipboard API is
222
+ * missing or blocked (Electron can deny it by policy). Returns success.
255
223
  */
256
224
  function legacyCopy(text) {
257
225
  try {
@@ -272,13 +240,10 @@ function legacyCopy(text) {
272
240
  }
273
241
  }
274
242
  /**
275
- * A collapsed-by-default hint listing the one-line command that registers
276
- * xtralab's running Jupyter MCP server with each installed agent that
277
- * supports `mcp add`. Copy-only: the user runs it in their own terminal,
278
- * where the server is reachable with no port to configure — the desktop
279
- * supervisor exports `JUPYTER_SERVER_MCP_URL`, and `pip` installs let the
280
- * proxy discover the server from its runtime file. Renders nothing when none
281
- * of those agents are on `$PATH`.
243
+ * Collapsed-by-default hint listing the `mcp add` one-liner per installed
244
+ * agent. Copy-only: run in the user's own terminal, where the proxy finds the
245
+ * server with no port (desktop exports `JUPYTER_SERVER_MCP_URL`; pip installs
246
+ * discover it from the runtime file). Renders nothing when no agent qualifies.
282
247
  */
283
248
  function McpSection(props) {
284
249
  const { trans } = props;
@@ -292,9 +257,6 @@ function McpSection(props) {
292
257
  window.setTimeout(() => setCopiedId(current => (current === id ? null : current)), 1500);
293
258
  };
294
259
  const copy = (command, id) => {
295
- // Prefer the async Clipboard API; fall back to `legacyCopy` when it's
296
- // missing or rejects (Electron can block it by policy). Flag "Copied" only
297
- // once a copy actually succeeds.
298
260
  const clipboard = navigator.clipboard;
299
261
  if (clipboard) {
300
262
  void clipboard.writeText(command).then(() => flagCopied(id), () => {
@@ -330,16 +292,8 @@ function McpSection(props) {
330
292
  trans.__('command.')))));
331
293
  }
332
294
  /**
333
- * The non-agent launch tiles — a plain terminal, a new notebook, and a
334
- * new console. They sit in a separate section below the agent grid so
335
- * they don't compete with the AI agents visually, and they're always
336
- * available regardless of the agent prompt textarea (which doesn't
337
- * apply to them).
338
- *
339
- * A terminal editor (Neovim, else Vim) joins the row when one is installed —
340
- * it opens in a terminal like the agents do, so it lives here rather than in
341
- * the agent grid. When neither is on `$PATH`, `editor` is `null` and no tile
342
- * renders.
295
+ * The non-agent launch tiles: terminal, notebook, and console, plus the
296
+ * terminal editor tile when one is installed (`editor` is `null` otherwise).
343
297
  */
344
298
  function OpenSection(props) {
345
299
  const { editor, onLaunchTerminal, onLaunchNotebook, onLaunchConsole, onLaunchEditor, trans } = props;
@@ -3,41 +3,29 @@ import { Token } from '@lumino/coreutils';
3
3
  import { ISignal } from '@lumino/signaling';
4
4
  import { type IEditor } from './editors';
5
5
  /**
6
- * A read-only, observable view of the launcher's terminal editors: xtralab's
7
- * built-ins (Neovim, Vim) merged with the user's `editors` setting, sorted by
8
- * rank, with disabled entries removed.
6
+ * A read-only, observable view of the launcher's terminal editors: the
7
+ * built-ins merged with the user's `editors` setting.
9
8
  */
10
9
  export interface IEditorRegistry {
11
10
  /**
12
- * The full merged editor list (disabled entries already removed). The
13
- * terminals panel uses it to badge a row for any configured editor that is
14
- * running, and to tell the server which editor commands to detect.
11
+ * The merged editor list (disabled entries removed); the terminals panel
12
+ * uses it to badge running editors.
15
13
  */
16
14
  readonly editors: IEditor[];
17
15
  /**
18
- * The single editor tile the launcher shows: the first editor, by rank, whose
19
- * command is on `$PATH` (Neovim before Vim by default), or `null` when none
20
- * qualifies.
16
+ * The single launcher tile: the first editor, by rank, whose command is on
17
+ * `$PATH`, or `null` when none qualifies.
21
18
  */
22
19
  readonly current: IEditor | null;
23
20
  /**
24
- * Emitted whenever {@link editors} or {@link current} changes (the user
25
- * edited the `editors` setting). Consumers that read on demand can ignore it.
21
+ * Emitted whenever {@link editors} or {@link current} changes.
26
22
  */
27
23
  readonly changed: ISignal<IEditorRegistry, void>;
28
24
  }
29
- /**
30
- * DI token for {@link IEditorRegistry}. Provided by `xtralab:editor-registry`
31
- * and consumed — optionally — by `xtralab:launcher` (for its tile) and
32
- * `xtralab:terminals` (to badge running editors with their logo).
33
- */
34
25
  export declare const IEditorRegistry: Token<IEditorRegistry>;
35
26
  /**
36
- * Provides {@link IEditorRegistry}: merges xtralab's built-in editors with the
37
- * user's `editors` setting, probes the server's `$PATH` to resolve the launcher
38
- * tile, and re-runs both on a settings change.
39
- *
40
- * `activate` awaits the first probe before returning, so a consumer reading
41
- * {@link IEditorRegistry.current} on activation sees a resolved tile.
27
+ * Provides {@link IEditorRegistry}: merges the built-in editors with the
28
+ * `editors` setting and probes the server's `$PATH`. `activate` awaits the
29
+ * first probe, so consumers see a resolved tile on activation.
42
30
  */
43
31
  export declare const editorRegistryPlugin: JupyterFrontEndPlugin<IEditorRegistry>;
@@ -4,15 +4,10 @@ import { Signal } from '@lumino/signaling';
4
4
  import { fetchAvailableCommands } from './availability';
5
5
  import { mergeEditors, resolveEditor } from './editors';
6
6
  import { LAUNCHER_PLUGIN_ID, registerLauncherSchemaDefaults } from './schemaDefaults';
7
- /**
8
- * DI token for {@link IEditorRegistry}. Provided by `xtralab:editor-registry`
9
- * and consumed — optionally — by `xtralab:launcher` (for its tile) and
10
- * `xtralab:terminals` (to badge running editors with their logo).
11
- */
12
7
  export const IEditorRegistry = new Token('xtralab:IEditorRegistry', '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.');
13
8
  /**
14
9
  * Concrete {@link IEditorRegistry}. The provider plugin is the only writer, so
15
- * the write side ({@link set}) is kept off the shared token.
10
+ * {@link set} is kept off the shared token.
16
11
  */
17
12
  class EditorRegistry {
18
13
  constructor() {
@@ -20,17 +15,26 @@ class EditorRegistry {
20
15
  this._current = null;
21
16
  this._changed = new Signal(this);
22
17
  }
18
+ /**
19
+ * The merged editor list (disabled entries removed).
20
+ */
23
21
  get editors() {
24
22
  return this._editors;
25
23
  }
24
+ /**
25
+ * The launcher-tile editor, or `null` when none qualifies.
26
+ */
26
27
  get current() {
27
28
  return this._current;
28
29
  }
30
+ /**
31
+ * Emitted whenever {@link editors} or {@link current} changes.
32
+ */
29
33
  get changed() {
30
34
  return this._changed;
31
35
  }
32
36
  /**
33
- * Replace both lists (recomputed together) and notify observers.
37
+ * Replace both lists and notify observers.
34
38
  */
35
39
  set(editors, current) {
36
40
  this._editors = editors;
@@ -39,12 +43,9 @@ class EditorRegistry {
39
43
  }
40
44
  }
41
45
  /**
42
- * Provides {@link IEditorRegistry}: merges xtralab's built-in editors with the
43
- * user's `editors` setting, probes the server's `$PATH` to resolve the launcher
44
- * tile, and re-runs both on a settings change.
45
- *
46
- * `activate` awaits the first probe before returning, so a consumer reading
47
- * {@link IEditorRegistry.current} on activation sees a resolved tile.
46
+ * Provides {@link IEditorRegistry}: merges the built-in editors with the
47
+ * `editors` setting and probes the server's `$PATH`. `activate` awaits the
48
+ * first probe, so consumers see a resolved tile on activation.
48
49
  */
49
50
  export const editorRegistryPlugin = {
50
51
  id: 'xtralab:editor-registry',
@@ -56,9 +57,6 @@ export const editorRegistryPlugin = {
56
57
  const registry = new EditorRegistry();
57
58
  const apply = async (overrides) => {
58
59
  const editors = mergeEditors(overrides);
59
- // Probe only the editors that opt into the availability check; entries
60
- // with `requireAvailable: false` (e.g. a shell alias) are shown
61
- // regardless and don't need a `which` lookup.
62
60
  const probe = Array.from(new Set(editors
63
61
  .filter(editor => editor.requireAvailable)
64
62
  .map(editor => editor.command)));
@@ -87,8 +85,6 @@ export const editorRegistryPlugin = {
87
85
  }
88
86
  catch (reason) {
89
87
  console.error('xtralab: failed to load editor settings', reason);
90
- // Settings load failed — fall back to the built-in editors so the
91
- // launcher tile still resolves instead of going silent.
92
88
  await apply([]);
93
89
  }
94
90
  }
@@ -1,10 +1,9 @@
1
1
  import { LabIcon } from '@jupyterlab/ui-components';
2
2
  /**
3
- * A terminal text editor surfaced on the launcher's "Open" section. An editor
4
- * takes no initial prompt and is launched by typing its command into a fresh
5
- * terminal (e.g. `nvim`). The launcher shows a single editor tile (the first
6
- * available candidate; see {@link resolveEditor}); the full list is shared with
7
- * the terminals panel to badge running editors.
3
+ * A terminal text editor on the launcher's "Open" section, launched by typing
4
+ * its command into a fresh terminal. The launcher shows one tile
5
+ * ({@link resolveEditor}); the full list badges running editors in the
6
+ * terminals panel.
8
7
  */
9
8
  export interface IEditor {
10
9
  /**
@@ -28,76 +27,71 @@ export interface IEditor {
28
27
  */
29
28
  icon: LabIcon;
30
29
  /**
31
- * Preference order for the single launcher tile: the first candidate, by
32
- * ascending rank, that qualifies wins (Neovim before Vim by default).
30
+ * Preference order: the first qualifying candidate by rank wins the tile.
33
31
  */
34
32
  rank: number;
35
33
  /**
36
- * When false, the launcher skips the `which`-based availability check for
37
- * this entry — useful for a shell alias or function that isn't on PATH but
38
- * still resolves when typed in a real terminal. Defaults to true.
34
+ * When false, skip the `which`-based availability check — for aliases or
35
+ * shell functions not on PATH. Defaults to true.
39
36
  */
40
37
  requireAvailable: boolean;
41
38
  }
42
39
  /**
43
- * The settings-side shape: every field except `id` is optional, so a user can
44
- * override a single field on a built-in editor (e.g. swap `vim`'s command for
45
- * a wrapper) without restating the whole entry. New ids define brand-new
46
- * editors. Mirrors `IAgentSettings` minus `promptArgs`.
40
+ * The settings-side shape: every field except `id` is optional so a user can
41
+ * override a single field on a built-in editor; new ids define new editors.
42
+ * Mirrors `IAgentSettings` minus `promptArgs`.
47
43
  */
48
44
  export interface IEditorSettings {
45
+ /**
46
+ * Id of the editor to override; a new id defines a new editor.
47
+ */
49
48
  id: string;
49
+ /**
50
+ * See {@link IEditor.label}.
51
+ */
50
52
  label?: string;
53
+ /**
54
+ * See {@link IEditor.caption}.
55
+ */
51
56
  caption?: string;
57
+ /**
58
+ * See {@link IEditor.command}.
59
+ */
52
60
  command?: string;
53
61
  /**
54
- * Inline SVG for a custom editor's icon. Required for new ids whose icon
55
- * isn't shipped with xtralab; ignored for built-in ids unless explicitly
56
- * set (in which case it overrides the built-in).
62
+ * Inline SVG icon. Required for new ids; overrides the built-in when set on
63
+ * a built-in id.
57
64
  */
58
65
  iconSvg?: string;
66
+ /**
67
+ * See {@link IEditor.rank}.
68
+ */
59
69
  rank?: number;
60
70
  /**
61
- * When false, the editor is hidden from the launcher's Open section (and no
62
- * longer recognised by the terminals panel). Disable both built-ins to drop
63
- * the editor tile entirely. Defaults to true.
71
+ * When false, hides the editor. Disable both built-ins to drop the editor
72
+ * tile entirely.
64
73
  */
65
74
  enabled?: boolean;
66
75
  /**
67
- * See {@link IEditor.requireAvailable}. Defaults to true for a built-in
68
- * editor that still uses its shipped command, and to false once you override
69
- * the `command` (a user-chosen command — often a shell alias — is trusted and
70
- * always shown). Set it explicitly to force the check on or off.
76
+ * See {@link IEditor.requireAvailable}. Defaults to true, but flips to false
77
+ * once `command` is overridden (a user-chosen alias is trusted).
71
78
  */
72
79
  requireAvailable?: boolean;
73
80
  }
74
81
  /**
75
- * The built-in editors projected into the JSON settings shape
76
- * ({@link IEditorSettings}), dropping the runtime-only {@link LabIcon}. Mirrors
77
- * {@link defaultAgentSettings}: {@link registerLauncherSchemaDefaults} injects
78
- * this as the `editors` setting's schema default so the Settings Editor shows
79
- * the shipped list.
82
+ * The built-in editors projected into the settings shape (no runtime LabIcon),
83
+ * injected as the `editors` schema default so the Settings Editor shows them.
80
84
  */
81
85
  export declare function defaultEditorSettings(): IEditorSettings[];
82
86
  /**
83
- * Merge xtralab's built-in editors with the user's `editors` settings. Built-in
84
- * entries keep their fields unless explicitly overridden; user-only entries are
85
- * appended. `enabled: false` filters an entry out of the result entirely (so
86
- * callers don't need to re-check the flag). The result is sorted by rank, which
87
- * is also the launcher's tile-preference order. Mirrors `mergeAgents`, including
88
- * turning `requireAvailable` off when the user overrides a built-in's `command`
89
- * so an aliased editor still shows.
87
+ * Merge the built-in editors with the user's `editors` settings; the result is
88
+ * sorted by rank, the tile-preference order. Mirrors `mergeAgents`, including
89
+ * turning `requireAvailable` off when a built-in's `command` is overridden.
90
90
  */
91
91
  export declare function mergeEditors(overrides: IEditorSettings[]): IEditor[];
92
92
  /**
93
- * Pick the single editor tile to show, given the merged editor list and the
94
- * set of commands known to be on `$PATH` (from the launcher's availability
95
- * probe). Returns the first candidate, by rank, that is either available or
96
- * opts out of the check (`requireAvailable: false`) — Neovim before Vim by
97
- * default — or `null` when none qualifies.
98
- *
99
- * When `available` is `null` (the endpoint couldn't be reached), a
100
- * `requireAvailable` editor is not shown; an entry with
101
- * `requireAvailable: false` is shown regardless.
93
+ * Pick the single tile: the first editor, by rank, that is available or opts
94
+ * out of the check, else `null`. When `available` is `null` (probe failed),
95
+ * only `requireAvailable: false` entries qualify.
102
96
  */
103
97
  export declare function resolveEditor(editors: IEditor[], available: Set<string> | null): IEditor | null;
@@ -1,11 +1,5 @@
1
1
  import { LabIcon, textEditorIcon } from '@jupyterlab/ui-components';
2
2
  import { BUILTIN_EDITOR_ICONS } from './icons';
3
- /**
4
- * Built-in editor candidates in preference order. The launcher shows the first
5
- * one whose command resolves on the server's `$PATH`, so Neovim wins over Vim
6
- * when both are installed. Users override, disable, or extend this list
7
- * through the `editors` setting; see {@link mergeEditors}.
8
- */
9
3
  const DEFAULTS = [
10
4
  {
11
5
  id: 'nvim',
@@ -27,11 +21,8 @@ const DEFAULTS = [
27
21
  }
28
22
  ];
29
23
  /**
30
- * The built-in editors projected into the JSON settings shape
31
- * ({@link IEditorSettings}), dropping the runtime-only {@link LabIcon}. Mirrors
32
- * {@link defaultAgentSettings}: {@link registerLauncherSchemaDefaults} injects
33
- * this as the `editors` setting's schema default so the Settings Editor shows
34
- * the shipped list.
24
+ * The built-in editors projected into the settings shape (no runtime LabIcon),
25
+ * injected as the `editors` schema default so the Settings Editor shows them.
35
26
  */
36
27
  export function defaultEditorSettings() {
37
28
  return DEFAULTS.map(editor => ({
@@ -54,13 +45,9 @@ function resolveEditorIcon(id, iconSvg) {
54
45
  return (_a = BUILTIN_EDITOR_ICONS[id]) !== null && _a !== void 0 ? _a : textEditorIcon;
55
46
  }
56
47
  /**
57
- * Merge xtralab's built-in editors with the user's `editors` settings. Built-in
58
- * entries keep their fields unless explicitly overridden; user-only entries are
59
- * appended. `enabled: false` filters an entry out of the result entirely (so
60
- * callers don't need to re-check the flag). The result is sorted by rank, which
61
- * is also the launcher's tile-preference order. Mirrors `mergeAgents`, including
62
- * turning `requireAvailable` off when the user overrides a built-in's `command`
63
- * so an aliased editor still shows.
48
+ * Merge the built-in editors with the user's `editors` settings; the result is
49
+ * sorted by rank, the tile-preference order. Mirrors `mergeAgents`, including
50
+ * turning `requireAvailable` off when a built-in's `command` is overridden.
64
51
  */
65
52
  export function mergeEditors(overrides) {
66
53
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
@@ -86,18 +73,11 @@ export function mergeEditors(overrides) {
86
73
  ? resolveEditorIcon(base.id, override.iconSvg)
87
74
  : base.icon,
88
75
  rank: (_d = override.rank) !== null && _d !== void 0 ? _d : base.rank,
89
- // See `mergeAgents`: once the user points a built-in editor at their own
90
- // command (e.g. a shell alias `which` can't resolve), stop requiring
91
- // availability so the tile still shows. The check stays on only while the
92
- // command is xtralab's default.
93
76
  requireAvailable: command === base.command
94
77
  ? ((_e = override.requireAvailable) !== null && _e !== void 0 ? _e : base.requireAvailable)
95
78
  : false
96
79
  });
97
80
  }
98
- // What remains in `overrideById` are ids that don't match a built-in — treat
99
- // them as new editors the user is adding. Skip disabled ones; the settings
100
- // schema validates the shape, so missing fields just fall back here.
101
81
  let nextRank = merged.reduce((max, editor) => Math.max(max, editor.rank), -1) + 1;
102
82
  for (const entry of overrideById.values()) {
103
83
  if (entry.enabled === false) {
@@ -119,15 +99,9 @@ export function mergeEditors(overrides) {
119
99
  return merged;
120
100
  }
121
101
  /**
122
- * Pick the single editor tile to show, given the merged editor list and the
123
- * set of commands known to be on `$PATH` (from the launcher's availability
124
- * probe). Returns the first candidate, by rank, that is either available or
125
- * opts out of the check (`requireAvailable: false`) — Neovim before Vim by
126
- * default — or `null` when none qualifies.
127
- *
128
- * When `available` is `null` (the endpoint couldn't be reached), a
129
- * `requireAvailable` editor is not shown; an entry with
130
- * `requireAvailable: false` is shown regardless.
102
+ * Pick the single tile: the first editor, by rank, that is available or opts
103
+ * out of the check, else `null`. When `available` is `null` (probe failed),
104
+ * only `requireAvailable: false` entries qualify.
131
105
  */
132
106
  export function resolveEditor(editors, available) {
133
107
  var _a;
@@ -1,15 +1,3 @@
1
1
  import { LabIcon } from '@jupyterlab/ui-components';
2
- /**
3
- * Built-in icons keyed by the agent's id, used to resolve the icon for an
4
- * agent declared without an inline `iconSvg` override (i.e. one of xtralab's
5
- * defaults). Custom agents added via settings can either supply their own
6
- * `iconSvg` or fall back to the generic terminal icon.
7
- */
8
2
  export declare const BUILTIN_AGENT_ICONS: Record<string, LabIcon>;
9
- /**
10
- * Built-in icons keyed by the editor's id, used to resolve the icon for a
11
- * built-in editor (Neovim, Vim) declared without an inline `iconSvg`. Custom
12
- * editors added via settings can supply their own `iconSvg` or fall back to
13
- * the generic text-editor icon.
14
- */
15
3
  export declare const BUILTIN_EDITOR_ICONS: Record<string, LabIcon>;