xtralab 0.14.1 → 0.15.1

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 (236) hide show
  1. package/README.md +10 -0
  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.d.ts +7 -0
  29. package/lib/customPanel/index.js +89 -0
  30. package/lib/editorBreadcrumbs/index.d.ts +3 -6
  31. package/lib/editorBreadcrumbs/index.js +10 -6
  32. package/lib/editorBreadcrumbs/widget.d.ts +17 -4
  33. package/lib/editorBreadcrumbs/widget.js +11 -17
  34. package/lib/editorIndent/index.d.ts +4 -12
  35. package/lib/editorIndent/index.js +8 -23
  36. package/lib/fileBrowser/commands.d.ts +28 -19
  37. package/lib/fileBrowser/commands.js +51 -98
  38. package/lib/fileBrowser/contents.d.ts +14 -0
  39. package/lib/fileBrowser/contents.js +28 -0
  40. package/lib/fileBrowser/dragAndDrop.d.ts +79 -0
  41. package/lib/fileBrowser/dragAndDrop.js +110 -0
  42. package/lib/fileBrowser/fileBrowser.d.ts +21 -9
  43. package/lib/fileBrowser/fileBrowser.js +211 -405
  44. package/lib/fileBrowser/gitStatus.d.ts +4 -9
  45. package/lib/fileBrowser/gitStatus.js +7 -17
  46. package/lib/fileBrowser/gitignore.d.ts +4 -17
  47. package/lib/fileBrowser/gitignore.js +4 -25
  48. package/lib/fileBrowser/icons.d.ts +7 -17
  49. package/lib/fileBrowser/icons.js +25 -80
  50. package/lib/fileBrowser/index.js +41 -10
  51. package/lib/fileBrowser/widget.d.ts +170 -53
  52. package/lib/fileBrowser/widget.js +242 -18
  53. package/lib/fileTypeIcons/index.js +0 -10
  54. package/lib/git/api.d.ts +5 -13
  55. package/lib/git/api.js +10 -36
  56. package/lib/git/askRequest.d.ts +4 -8
  57. package/lib/git/askRequest.js +6 -20
  58. package/lib/git/commands.d.ts +40 -5
  59. package/lib/git/commands.js +16 -10
  60. package/lib/git/diffModel.js +4 -0
  61. package/lib/git/diffSurface.d.ts +41 -55
  62. package/lib/git/diffSurface.js +42 -117
  63. package/lib/git/diffWidget.d.ts +81 -2
  64. package/lib/git/diffWidget.js +62 -12
  65. package/lib/git/imageDiff.d.ts +5 -6
  66. package/lib/git/imageDiff.js +18 -48
  67. package/lib/git/index.d.ts +0 -3
  68. package/lib/git/index.js +3 -8
  69. package/lib/git/notebookDiff.d.ts +110 -33
  70. package/lib/git/notebookDiff.js +52 -195
  71. package/lib/git/tokens.d.ts +73 -31
  72. package/lib/git/tokens.js +2 -3
  73. package/lib/highlight/index.d.ts +4 -10
  74. package/lib/highlight/index.js +10 -41
  75. package/lib/index.d.ts +0 -9
  76. package/lib/index.js +2 -9
  77. package/lib/launcher/agents.d.ts +55 -51
  78. package/lib/launcher/agents.js +25 -54
  79. package/lib/launcher/availability.d.ts +3 -9
  80. package/lib/launcher/availability.js +3 -9
  81. package/lib/launcher/commands.d.ts +7 -32
  82. package/lib/launcher/commands.js +14 -45
  83. package/lib/launcher/dashboard.d.ts +19 -24
  84. package/lib/launcher/dashboard.js +21 -67
  85. package/lib/launcher/editorRegistry.d.ts +10 -22
  86. package/lib/launcher/editorRegistry.js +14 -18
  87. package/lib/launcher/editors.d.ts +39 -45
  88. package/lib/launcher/editors.js +8 -34
  89. package/lib/launcher/icons.d.ts +0 -12
  90. package/lib/launcher/icons.js +14 -37
  91. package/lib/launcher/index.js +12 -55
  92. package/lib/launcher/invocation.d.ts +4 -10
  93. package/lib/launcher/invocation.js +7 -22
  94. package/lib/launcher/registry.d.ts +9 -7
  95. package/lib/launcher/registry.js +9 -7
  96. package/lib/launcher/schemaDefaults.d.ts +2 -9
  97. package/lib/launcher/schemaDefaults.js +37 -13
  98. package/lib/launcher/tokens.d.ts +10 -22
  99. package/lib/launcher/tokens.js +5 -8
  100. package/lib/menuBar/index.d.ts +3 -10
  101. package/lib/menuBar/index.js +11 -28
  102. package/lib/menus/index.d.ts +3 -9
  103. package/lib/menus/index.js +14 -30
  104. package/lib/omnibox/files.d.ts +2 -4
  105. package/lib/omnibox/files.js +5 -11
  106. package/lib/omnibox/index.d.ts +4 -14
  107. package/lib/omnibox/index.js +9 -27
  108. package/lib/omnibox/model.d.ts +38 -10
  109. package/lib/omnibox/model.js +15 -33
  110. package/lib/omnibox/recents.d.ts +15 -17
  111. package/lib/omnibox/recents.js +12 -17
  112. package/lib/omnibox/tokens.d.ts +5 -10
  113. package/lib/omnibox/tokens.js +2 -6
  114. package/lib/omnibox/widget.d.ts +11 -7
  115. package/lib/omnibox/widget.js +8 -16
  116. package/lib/searchReplace/index.d.ts +4 -20
  117. package/lib/searchReplace/index.js +7 -27
  118. package/lib/showOutput/index.d.ts +3 -12
  119. package/lib/showOutput/index.js +6 -22
  120. package/lib/sidebar/index.d.ts +4 -13
  121. package/lib/sidebar/index.js +73 -46
  122. package/lib/terminalNotifications/index.d.ts +4 -10
  123. package/lib/terminalNotifications/index.js +6 -20
  124. package/lib/terminals/agentTerminals.d.ts +12 -5
  125. package/lib/terminals/agentTerminals.js +25 -44
  126. package/lib/terminals/detection.d.ts +4 -8
  127. package/lib/terminals/detection.js +4 -8
  128. package/lib/terminals/index.d.ts +0 -33
  129. package/lib/terminals/index.js +24 -102
  130. package/lib/terminals/model.d.ts +64 -139
  131. package/lib/terminals/model.js +80 -220
  132. package/lib/terminals/tokens.d.ts +11 -22
  133. package/lib/terminals/tokens.js +2 -2
  134. package/lib/terminals/widget.d.ts +72 -38
  135. package/lib/terminals/widget.js +173 -73
  136. package/lib/topBar/icons.d.ts +3 -8
  137. package/lib/topBar/icons.js +3 -8
  138. package/lib/topBar/index.d.ts +4 -11
  139. package/lib/topBar/index.js +10 -38
  140. package/lib/walkthrough/index.d.ts +4 -9
  141. package/lib/walkthrough/index.js +6 -20
  142. package/lib/walkthrough/panel.d.ts +40 -9
  143. package/lib/walkthrough/panel.js +4 -10
  144. package/package.json +2 -2
  145. package/schema/launcher.json +2 -2
  146. package/schema/sidebar.json +47 -7
  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 +119 -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 +70 -98
  165. package/src/fileBrowser/contents.ts +33 -0
  166. package/src/fileBrowser/dragAndDrop.ts +188 -0
  167. package/src/fileBrowser/fileBrowser.tsx +259 -440
  168. package/src/fileBrowser/gitStatus.ts +7 -17
  169. package/src/fileBrowser/gitignore.ts +4 -25
  170. package/src/fileBrowser/icons.ts +25 -80
  171. package/src/fileBrowser/index.ts +43 -10
  172. package/src/fileBrowser/widget.tsx +344 -64
  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 +70 -10
  177. package/src/git/diffModel.ts +25 -0
  178. package/src/git/diffSurface.tsx +71 -159
  179. package/src/git/diffWidget.tsx +104 -14
  180. package/src/git/imageDiff.tsx +45 -51
  181. package/src/git/index.ts +3 -8
  182. package/src/git/notebookDiff.tsx +211 -238
  183. package/src/git/tokens.ts +73 -31
  184. package/src/highlight/index.ts +10 -41
  185. package/src/index.ts +2 -9
  186. package/src/launcher/agents.ts +74 -92
  187. package/src/launcher/availability.ts +3 -9
  188. package/src/launcher/commands.ts +14 -51
  189. package/src/launcher/dashboard.tsx +49 -88
  190. package/src/launcher/editorRegistry.ts +21 -29
  191. package/src/launcher/editors.ts +39 -58
  192. package/src/launcher/icons.ts +15 -37
  193. package/src/launcher/index.ts +12 -55
  194. package/src/launcher/invocation.ts +7 -22
  195. package/src/launcher/registry.ts +9 -7
  196. package/src/launcher/schemaDefaults.ts +43 -13
  197. package/src/launcher/tokens.ts +10 -22
  198. package/src/menuBar/index.ts +11 -28
  199. package/src/menus/index.ts +14 -30
  200. package/src/omnibox/files.ts +10 -14
  201. package/src/omnibox/index.ts +9 -27
  202. package/src/omnibox/model.ts +50 -38
  203. package/src/omnibox/recents.ts +17 -22
  204. package/src/omnibox/tokens.ts +5 -10
  205. package/src/omnibox/widget.tsx +14 -19
  206. package/src/searchReplace/index.ts +7 -27
  207. package/src/showOutput/index.ts +6 -22
  208. package/src/sidebar/index.ts +103 -52
  209. package/src/terminalNotifications/index.ts +42 -25
  210. package/src/terminals/agentTerminals.ts +25 -49
  211. package/src/terminals/detection.ts +4 -8
  212. package/src/terminals/index.ts +31 -102
  213. package/src/terminals/model.ts +130 -246
  214. package/src/terminals/tokens.ts +11 -22
  215. package/src/terminals/widget.tsx +229 -113
  216. package/src/topBar/icons.ts +3 -8
  217. package/src/topBar/index.ts +21 -44
  218. package/src/walkthrough/index.ts +6 -20
  219. package/src/walkthrough/panel.ts +40 -10
  220. package/style/about.css +2 -7
  221. package/style/askAgent.css +8 -40
  222. package/style/base.css +25 -73
  223. package/style/chrome.css +108 -308
  224. package/style/commandBar.css +4 -20
  225. package/style/customPanel.css +6 -0
  226. package/style/git.css +22 -184
  227. package/style/highlight.css +1 -3
  228. package/style/index.js +1 -0
  229. package/style/launcher.css +6 -70
  230. package/style/omnibox.css +2 -14
  231. package/style/showOutput.css +0 -6
  232. package/style/sidebar.css +29 -9
  233. package/style/tabs.css +5 -13
  234. package/style/terminals.css +18 -123
  235. package/style/topBar.css +2 -22
  236. package/style/walkthrough.css +0 -8
@@ -10,24 +10,14 @@ const PLUGIN_ID = 'xtralab:menu-bar';
10
10
  const OPEN_COMMAND = 'xtralab:open-main-menu';
11
11
  const TOGGLE_COMMAND = 'xtralab:toggle-menu-bar';
12
12
  /**
13
- * How long after the popup closes a button press still counts as "close
14
- * only". An open Lumino menu closes itself on any outside press from a
15
- * document `pointerdown` listener in the capture phase, which runs before
16
- * the button's own mousedown handler — so without this window, pressing the
17
- * button while the popup is open would close it and instantly reopen it.
13
+ * Guard after the popup closes: Lumino menus close on a capture-phase document
14
+ * pointerdown, before the button's mousedown, which would instantly reopen.
18
15
  */
19
16
  const REOPEN_GUARD_MS = 250;
20
17
  /**
21
- * Collapse the main menu bar into a compact menu button.
22
- *
23
- * The menu bar is hidden and a hamburger button in the top bar opens the same
24
- * menus as a vertical popup. The popup reuses the live `RankedMenu` instances
25
- * owned by the `MainMenu`, so menus added or removed at runtime are reflected
26
- * without duplication.
27
- *
28
- * Hiding covers the `jp-menu-panel` container too, which has its own
29
- * `min-height` and would otherwise leave an empty strip. The "Show Menu Bar"
30
- * toggle restores the classic bar.
18
+ * Collapse the main menu bar into a hamburger button whose popup reuses the
19
+ * live `RankedMenu` instances owned by `MainMenu`. Hiding covers the
20
+ * `jp-menu-panel` container too — its `min-height` would leave an empty strip.
31
21
  */
32
22
  const plugin = {
33
23
  id: PLUGIN_ID,
@@ -64,9 +54,8 @@ const plugin = {
64
54
  const openMenu = () => {
65
55
  var _a, _b;
66
56
  if (visible) {
67
- // The classic bar is on screen; behave like keyboard menu
68
- // activation instead of opening a redundant popup that would
69
- // compete with the bar for the same Menu instances.
57
+ // With the classic bar on screen, act like keyboard menu activation —
58
+ // a popup would compete with the bar for the same Menu instances.
70
59
  mainMenu.activeIndex = 0;
71
60
  mainMenu.openActiveMenu();
72
61
  return;
@@ -74,13 +63,8 @@ const plugin = {
74
63
  if (Date.now() - popupClosedAt < REOPEN_GUARD_MS) {
75
64
  return;
76
65
  }
77
- // One popup instance, rebuilt from the bar's current menus on every
78
- // open so runtime menu changes stay reflected. It is a plain Lumino
79
- // Menu rather than a MenuSvg: MenuSvg.insertItem re-wraps each
80
- // submenu's renderer and insertItem on every call, which would pile
81
- // wrappers onto the shared menus across reopens. The svg renderer and
82
- // themed-container class are applied directly instead, matching how
83
- // the real menus are constructed in MainMenu.
66
+ // A plain Menu rebuilt on every open; MenuSvg.insertItem would re-wrap
67
+ // each submenu's renderer per reopen, piling wrappers onto the shared menus.
84
68
  if (popup === null) {
85
69
  popup = new Menu({ commands, renderer: MenuSvg.defaultRenderer });
86
70
  popup.addClass('jp-ThemedContainer');
@@ -153,9 +137,8 @@ const plugin = {
153
137
  loaded.changed.connect(update);
154
138
  })
155
139
  .catch(reason => {
156
- // Without settings the collapsed state cannot be managed (and the
157
- // button was never added) — reveal the stock bar rather than leave
158
- // the app with no reachable menus.
140
+ // Without settings the collapsed state cannot be managed and the button
141
+ // was never added; reveal the stock bar so menus stay reachable.
159
142
  applyVisibility(true);
160
143
  console.error(`Failed to load settings for ${PLUGIN_ID}`, reason);
161
144
  });
@@ -1,14 +1,8 @@
1
1
  import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
2
  /**
3
- * Hide the "Run" and "Kernel" top-level menus while no kernel-using widget
4
- * is open in the main area. The agent-first launcher does not use kernels,
5
- * so showing those menus on a fresh workspace surfaces commands the user
6
- * cannot meaningfully invoke; remove them until a notebook or console is
7
- * opened, then restore them at their original ranks.
8
- *
9
- * Detection is duck-typed on `sessionContext`: NotebookPanel and ConsolePanel
10
- * both expose it, which avoids pulling in `@jupyterlab/notebook` and
11
- * `@jupyterlab/console` just to identify their widgets.
3
+ * Hide the Run and Kernel menus while no kernel-using widget is open in the
4
+ * main area, then restore them at their original ranks — the agent-first
5
+ * launcher does not use kernels, so a fresh workspace should not surface them.
12
6
  */
13
7
  declare const plugin: JupyterFrontEndPlugin<void>;
14
8
  export default plugin;
@@ -2,15 +2,9 @@ import { ILabShell } from '@jupyterlab/application';
2
2
  import { IMainMenu } from '@jupyterlab/mainmenu';
3
3
  const PLUGIN_ID = 'xtralab:menus';
4
4
  /**
5
- * Hide the "Run" and "Kernel" top-level menus while no kernel-using widget
6
- * is open in the main area. The agent-first launcher does not use kernels,
7
- * so showing those menus on a fresh workspace surfaces commands the user
8
- * cannot meaningfully invoke; remove them until a notebook or console is
9
- * opened, then restore them at their original ranks.
10
- *
11
- * Detection is duck-typed on `sessionContext`: NotebookPanel and ConsolePanel
12
- * both expose it, which avoids pulling in `@jupyterlab/notebook` and
13
- * `@jupyterlab/console` just to identify their widgets.
5
+ * Hide the Run and Kernel menus while no kernel-using widget is open in the
6
+ * main area, then restore them at their original ranks — the agent-first
7
+ * launcher does not use kernels, so a fresh workspace should not surface them.
14
8
  */
15
9
  const plugin = {
16
10
  id: PLUGIN_ID,
@@ -19,27 +13,21 @@ const plugin = {
19
13
  requires: [IMainMenu, ILabShell],
20
14
  activate: (app, mainMenu, labShell) => {
21
15
  var _a, _b;
22
- // The interface types (IRunMenu, IKernelMenu) extend IRankedMenu, but
23
- // the concrete instances are RankedMenu/Menu — cast so we can hand them
24
- // to MenuBar.removeMenu and IMainMenu.addMenu, which expect a `Menu`.
16
+ // The interface types extend IRankedMenu but the concrete instances are
17
+ // RankedMenu/Menu; cast for the MenuBar methods, which expect a `Menu`.
25
18
  const menuBar = mainMenu;
26
19
  const runMenu = mainMenu.runMenu;
27
20
  const kernelMenu = mainMenu.kernelMenu;
28
- // Capture the schema-assigned ranks so the menus reappear in their
29
- // original slots between View (rank 3) and Tabs (rank 500). Falling
30
- // back to the hard-coded defaults from `MainMenu` keeps things sane
31
- // if the schema ever omits the rank.
21
+ // Schema-assigned ranks so the menus reappear in their original slots;
22
+ // fall back to MainMenu's hard-coded defaults if the schema omits them.
32
23
  const runRank = (_a = mainMenu.runMenu.rank) !== null && _a !== void 0 ? _a : 4;
33
24
  const kernelRank = (_b = mainMenu.kernelMenu.rank) !== null && _b !== void 0 ? _b : 5;
34
25
  const isPresent = (menu) => Array.from(menuBar.menus).indexOf(menu) > -1;
35
26
  const update = () => {
36
27
  const show = hasKernelWidget(labShell);
37
28
  if (show) {
38
- // Don't go through `mainMenu.addMenu`: it picks the insertion index
39
- // from a private `_items` array that `removeMenu` doesn't update,
40
- // so re-adding lands the menu at the wrong position. Insert
41
- // directly on the MenuBar by walking current menus and finding
42
- // the first sibling with a higher rank.
29
+ // Not `mainMenu.addMenu`: its insertion index comes from a private
30
+ // `_items` array that `removeMenu` doesn't update, misplacing re-adds.
43
31
  if (!isPresent(runMenu)) {
44
32
  insertByRank(menuBar, runMenu, runRank);
45
33
  }
@@ -63,11 +51,9 @@ const plugin = {
63
51
  }
64
52
  };
65
53
  /**
66
- * True iff any widget in the main area exposes a `sessionContext` — the
67
- * shared marker for NotebookPanel, ConsolePanel, and kernel-attached file
68
- * editors. We don't import their concrete types because that would drag
69
- * `@jupyterlab/notebook` and `@jupyterlab/console` into xtralab's bundle
70
- * just to do an `instanceof` check.
54
+ * True iff any main-area widget exposes a `sessionContext` (NotebookPanel,
55
+ * ConsolePanel, kernel-attached editors) — duck-typed to keep
56
+ * `@jupyterlab/notebook` and `@jupyterlab/console` out of the bundle.
71
57
  */
72
58
  function hasKernelWidget(labShell) {
73
59
  for (const widget of labShell.widgets('main')) {
@@ -82,10 +68,8 @@ function hasSessionContext(widget) {
82
68
  return (candidate.sessionContext !== null && candidate.sessionContext !== undefined);
83
69
  }
84
70
  /**
85
- * Insert `menu` into `menuBar` at the position dictated by `rank`, using
86
- * the existing menus' ranks to find the slot. Menus without a numeric
87
- * rank are treated as +Infinity so they sink to the end (matching the
88
- * convention in `MenuFactory.createMenus`).
71
+ * Insert `menu` at the slot dictated by `rank`; rank-less menus count as
72
+ * +Infinity and sink to the end, matching `MenuFactory.createMenus`.
89
73
  */
90
74
  function insertByRank(menuBar, menu, rank) {
91
75
  const menus = menuBar.menus;
@@ -1,7 +1,5 @@
1
1
  /**
2
- * The workspace file list, cached briefly so reopening the omnibox in quick
3
- * succession reuses one scan. A failed fetch (e.g. quickopen's server
4
- * extension is absent) resolves to an empty list so file search degrades to
5
- * "no results" instead of surfacing an error.
2
+ * The workspace file list, cached briefly so reopening the omnibox reuses one
3
+ * scan. A failed fetch resolves to an empty list.
6
4
  */
7
5
  export declare function loadWorkspaceFiles(): Promise<string[]>;
@@ -2,13 +2,9 @@ import { URLExt } from '@jupyterlab/coreutils';
2
2
  import { ServerConnection } from '@jupyterlab/services';
3
3
  /**
4
4
  * Fetch and flatten the workspace file list from `jupyterlab-quickopen`'s
5
- * server endpoint (`GET {base}/jupyterlab-quickopen/api/files`).
6
- *
7
- * We reuse quickopen's endpoint rather than walking the contents API so the
8
- * listing honors the same server-side `.gitignore` filtering quickopen does
9
- * (xtralab ships `respectGitignore: true`) in a single request. The endpoint
10
- * only exists when quickopen's server extension is installed and the server
11
- * reads a local filesystem; callers treat a rejection as "no file results".
5
+ * server endpoint, which applies server-side `.gitignore` filtering in one
6
+ * request. Rejects when the server extension is absent; callers treat that as
7
+ * "no file results".
12
8
  */
13
9
  async function fetchWorkspaceFiles(respectGitignore = true) {
14
10
  const settings = ServerConnection.makeSettings();
@@ -36,10 +32,8 @@ async function fetchWorkspaceFiles(respectGitignore = true) {
36
32
  const CACHE_TTL_MS = 15000;
37
33
  let cache = null;
38
34
  /**
39
- * The workspace file list, cached briefly so reopening the omnibox in quick
40
- * succession reuses one scan. A failed fetch (e.g. quickopen's server
41
- * extension is absent) resolves to an empty list so file search degrades to
42
- * "no results" instead of surfacing an error.
35
+ * The workspace file list, cached briefly so reopening the omnibox reuses one
36
+ * scan. A failed fetch resolves to an empty list.
43
37
  */
44
38
  export function loadWorkspaceFiles() {
45
39
  const now = Date.now();
@@ -1,20 +1,10 @@
1
1
  import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
2
  import { IOmnibox } from './tokens';
3
3
  /**
4
- * The omnibox: a single launcher overlay that fuzzy-searches workspace files
5
- * (via jupyterlab-quickopen's gitignore-aware endpoint) and JupyterLab
6
- * commands (the command palette's entries plus registry commands the palette
7
- * doesn't list), and routes a typed prompt to one of the configured agents
8
- * (running it in a fresh terminal through the launcher's
9
- * `xtralab:start-agent:<id>` commands). It is opened by the top-bar command
10
- * bar.
11
- *
12
- * Commands run and files opened through the overlay are remembered (persisted
13
- * in the state database) and offered again at the top while the query is
14
- * empty; the `maxNumberRecents` setting caps how many of each are kept.
15
- *
16
- * The agent rows come from the launcher's `IAgentRegistry`; when the launcher
17
- * is disabled the omnibox still searches files and commands.
4
+ * The omnibox: a launcher overlay that fuzzy-searches workspace files and
5
+ * commands and routes a typed prompt to a configured agent in a fresh
6
+ * terminal. Recently used commands and files persist in the state database;
7
+ * without the launcher it still searches files and commands.
18
8
  */
19
9
  declare const plugin: JupyterFrontEndPlugin<IOmnibox>;
20
10
  export default plugin;
@@ -9,20 +9,10 @@ import { IOmnibox, OMNIBOX_OPEN_COMMAND } from './tokens';
9
9
  import { OmniboxWidget } from './widget';
10
10
  const PLUGIN_ID = 'xtralab:omnibox';
11
11
  /**
12
- * The omnibox: a single launcher overlay that fuzzy-searches workspace files
13
- * (via jupyterlab-quickopen's gitignore-aware endpoint) and JupyterLab
14
- * commands (the command palette's entries plus registry commands the palette
15
- * doesn't list), and routes a typed prompt to one of the configured agents
16
- * (running it in a fresh terminal through the launcher's
17
- * `xtralab:start-agent:<id>` commands). It is opened by the top-bar command
18
- * bar.
19
- *
20
- * Commands run and files opened through the overlay are remembered (persisted
21
- * in the state database) and offered again at the top while the query is
22
- * empty; the `maxNumberRecents` setting caps how many of each are kept.
23
- *
24
- * The agent rows come from the launcher's `IAgentRegistry`; when the launcher
25
- * is disabled the omnibox still searches files and commands.
12
+ * The omnibox: a launcher overlay that fuzzy-searches workspace files and
13
+ * commands and routes a typed prompt to a configured agent in a fresh
14
+ * terminal. Recently used commands and files persist in the state database;
15
+ * without the launcher it still searches files and commands.
26
16
  */
27
17
  const plugin = {
28
18
  id: PLUGIN_ID,
@@ -40,21 +30,15 @@ const plugin = {
40
30
  const { commands, docRegistry } = app;
41
31
  const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('jupyterlab');
42
32
  const placeholder = trans.__('Search files and commands, or ask an agent…');
43
- // The palette's items carry per-item args (e.g. one "Use Theme: …" per
44
- // theme) that a raw command-registry scan can't see, but `ICommandPalette`
45
- // exposes no item list and the widget itself is unreachable through the
46
- // shell (`LabShell.add` defers it until layout restore, after which the
47
- // modal setting re-parents it out of the left area). The wrapper's
48
- // `_palette` field is private in TypeScript only, so read it guarded.
33
+ // `ICommandPalette` exposes no item list and the palette widget is
34
+ // unreachable through the shell; duck-read the wrapper's TS-only-private `_palette`.
49
35
  const paletteItems = () => {
50
36
  const widget = palette === null || palette === void 0 ? void 0 : palette._palette;
51
37
  return widget instanceof CommandPalette ? [...widget.items] : [];
52
38
  };
53
39
  const recents = new OmniboxRecents({ state });
54
- // Restore the persisted recents only after the configured cap is known:
55
- // `restore` trims to `maxItems`, so restoring at the constructor default
56
- // would permanently drop entries beyond it whenever the user configured a
57
- // larger cap and the state fetch won the race against the settings load.
40
+ // Restore only after the configured cap is known: `restore` trims to
41
+ // `maxItems`, so restoring at the default could permanently drop entries.
58
42
  if (settingRegistry) {
59
43
  void settingRegistry
60
44
  .load(PLUGIN_ID)
@@ -85,7 +69,7 @@ const plugin = {
85
69
  };
86
70
  const open = (query) => {
87
71
  // Reopen fresh each time so the input resets and the agent snapshot is
88
- // current; the file list is cached separately (see files.ts).
72
+ // current; the file list stays cached (files.ts).
89
73
  close();
90
74
  const widget = new OmniboxWidget({
91
75
  commands,
@@ -110,7 +94,6 @@ const plugin = {
110
94
  label: trans.__('Search…'),
111
95
  caption: trans.__('Search files and commands, or ask an agent'),
112
96
  execute: args => {
113
- // Toggle: a second press (e.g. of the keyboard shortcut) closes it.
114
97
  if (current && !current.isDisposed) {
115
98
  close();
116
99
  return;
@@ -119,7 +102,6 @@ const plugin = {
119
102
  open(typeof query === 'string' ? query : undefined);
120
103
  }
121
104
  });
122
- // Open the omnibox with Cmd/Ctrl+K, the common "command center" chord.
123
105
  commands.addKeyBinding({
124
106
  command: OMNIBOX_OPEN_COMMAND,
125
107
  keys: ['Accel K'],
@@ -5,14 +5,14 @@ import type { CommandRegistry } from '@lumino/commands';
5
5
  import type { CommandPalette } from '@lumino/widgets';
6
6
  import type { IAgent } from '../launcher/agents';
7
7
  import type { OmniboxRecents } from './recents';
8
- /**
9
- * The source a result row came from, used to group rows under a header.
10
- */
11
8
  type OmniboxItemKind = 'command' | 'file' | 'agent';
12
9
  /**
13
10
  * A single result row, with the action it runs when chosen.
14
11
  */
15
12
  export interface IOmniboxItem {
13
+ /**
14
+ * The source category of the row: command, file, or agent.
15
+ */
16
16
  kind: OmniboxItemKind;
17
17
  /**
18
18
  * Stable React key.
@@ -47,34 +47,62 @@ interface IOmniboxSections {
47
47
  * Recently used commands and files, shown while the term is empty.
48
48
  */
49
49
  recent: IOmniboxItem[];
50
+ /**
51
+ * Commands matching the term.
52
+ */
50
53
  commands: IOmniboxItem[];
54
+ /**
55
+ * Workspace files matching the term.
56
+ */
51
57
  files: IOmniboxItem[];
58
+ /**
59
+ * Per-agent "Ask" rows carrying the term as a prompt.
60
+ */
52
61
  agents: IOmniboxItem[];
53
62
  }
63
+ /**
64
+ * Inputs for {@link computeSections}.
65
+ */
54
66
  interface IComputeOptions {
67
+ /**
68
+ * Raw query text from the input.
69
+ */
55
70
  query: string;
71
+ /**
72
+ * The command registry used to look up and execute commands.
73
+ */
56
74
  commands: CommandRegistry;
57
75
  /**
58
- * The command palette's items, whose labels are computed with each item's
59
- * args — the only form in which entries like "Use Theme: …" exist.
76
+ * Palette items, whose labels are computed with each item's args — the only
77
+ * form in which entries like "Use Theme: …" exist.
60
78
  */
61
79
  paletteItems: ReadonlyArray<CommandPalette.IItem>;
80
+ /**
81
+ * The document registry used to pick file icons.
82
+ */
62
83
  docRegistry: DocumentRegistry;
84
+ /**
85
+ * The available agents; prompt-capable ones get "Ask" rows.
86
+ */
63
87
  agents: IAgent[];
88
+ /**
89
+ * Workspace-relative file paths to match against.
90
+ */
64
91
  files: string[];
65
92
  /**
66
93
  * Recently-used tracker; `null` disables the recent rows and recording.
67
94
  */
68
95
  recents: OmniboxRecents | null;
96
+ /**
97
+ * Translation bundle for row labels.
98
+ */
69
99
  trans: TranslationBundle;
70
100
  }
71
101
  /**
72
102
  * Build the grouped result set for a query. A leading `>` searches only
73
- * commands and a leading `/` only files; otherwise commands and files are
74
- * fuzzy-matched and every prompt-capable agent is offered an "Ask" row
75
- * carrying the query as its prompt. An empty term yields the recently used
76
- * rows for the active mode instead (and the widget shows a hint when there
77
- * are none).
103
+ * commands, `/` only files; otherwise every prompt-capable agent also gets an
104
+ * "Ask" row carrying the query as its prompt. An empty term yields the
105
+ * recently used rows for the active mode.
78
106
  */
79
107
  export declare function computeSections(options: IComputeOptions): IOmniboxSections;
80
108
  export {};
@@ -3,20 +3,14 @@ import { StringExt } from '@lumino/algorithm';
3
3
  import { agentCommandId } from '../launcher/tokens';
4
4
  const COMMAND_LIMIT = 7;
5
5
  const FILE_LIMIT = 10;
6
- /**
7
- * Prefixes that narrow the search to a single source: a leading `>` to
8
- * commands, a leading `/` to files (relative paths never start with `/`, so it
9
- * is unambiguous). Without a prefix, every source is searched.
10
- */
11
6
  const COMMAND_PREFIX = '>';
7
+ // Unambiguous: workspace-relative paths never start with '/'.
12
8
  const FILE_PREFIX = '/';
13
9
  /**
14
10
  * Build the grouped result set for a query. A leading `>` searches only
15
- * commands and a leading `/` only files; otherwise commands and files are
16
- * fuzzy-matched and every prompt-capable agent is offered an "Ask" row
17
- * carrying the query as its prompt. An empty term yields the recently used
18
- * rows for the active mode instead (and the widget shows a hint when there
19
- * are none).
11
+ * commands, `/` only files; otherwise every prompt-capable agent also gets an
12
+ * "Ask" row carrying the query as its prompt. An empty term yields the
13
+ * recently used rows for the active mode.
20
14
  */
21
15
  export function computeSections(options) {
22
16
  const { query, commands, agents, trans } = options;
@@ -43,13 +37,11 @@ export function computeSections(options) {
43
37
  recent: [],
44
38
  commands: mode === 'files' ? [] : matchCommands(options, term),
45
39
  files: mode === 'commands' ? [] : matchFiles(options, term),
46
- // Agents only in the unprefixed view; the prompt is the full typed query.
47
40
  agents: mode === 'all' ? buildAgentItems(commands, agents, term, trans) : []
48
41
  };
49
42
  }
50
43
  /**
51
- * Run a command and record the use on success, so failed commands never enter
52
- * the recents list.
44
+ * Run a command and record the use on success, so failures never enter the recents.
53
45
  */
54
46
  function executeCommand(commands, recents, id, args) {
55
47
  void commands
@@ -61,9 +53,6 @@ function executeCommand(commands, recents, id, args) {
61
53
  console.error(`xtralab omnibox: command "${id}" failed`, reason);
62
54
  });
63
55
  }
64
- /**
65
- * Open a file and record the use on success.
66
- */
67
56
  function openFile(commands, recents, path) {
68
57
  void commands
69
58
  .execute('docmanager:open', { path })
@@ -76,9 +65,8 @@ function openFile(commands, recents, path) {
76
65
  }
77
66
  /**
78
67
  * Read a command's label, visibility and caption, or `null` when the command
79
- * is missing, hidden, label-less, or its accessors throw (a command's
80
- * accessors can assume a context — e.g. an active notebook — the omnibox
81
- * doesn't provide).
68
+ * is missing, hidden, label-less, or its accessors throw (they can assume a
69
+ * context the omnibox doesn't provide).
82
70
  */
83
71
  function commandDisplay(commands, id, args) {
84
72
  if (!commands.hasCommand(id)) {
@@ -97,10 +85,9 @@ function commandDisplay(commands, id, args) {
97
85
  }
98
86
  /**
99
87
  * The recently used rows for the empty term: both kinds interleaved by
100
- * recency in the unprefixed view, or only the mode's kind under a bare `>` or
101
- * `/`. Commands that no longer resolve are dropped, as are files missing from
102
- * the loaded workspace listing (while the listing is still loading — or
103
- * unavailable — file entries are shown as recorded).
88
+ * recency, or only the mode's kind under a bare `>` or `/`. Unresolvable
89
+ * commands are dropped, as are files absent from the workspace listing once
90
+ * it loads.
104
91
  */
105
92
  function buildRecentItems(options, mode) {
106
93
  var _a;
@@ -147,11 +134,10 @@ function buildRecentItems(options, mode) {
147
134
  return items;
148
135
  }
149
136
  /**
150
- * Match the query against the palette's items first — their labels carry each
151
- * item's args (one "Use Theme: …" per theme, one row per font-size key), which
152
- * a raw registry scan can never produce — then against registry commands the
153
- * palette doesn't present. Palette-covered ids are skipped in the registry
154
- * pass so a command never also surfaces under its argless label.
137
+ * Match palette items first — their labels carry per-item args (one "Use
138
+ * Theme: …" per theme), which a registry scan can never produce — then
139
+ * registry commands the palette doesn't present, skipping palette-covered ids
140
+ * so a command never also surfaces under its argless label.
155
141
  */
156
142
  function matchCommands(options, term) {
157
143
  const { commands, paletteItems, recents } = options;
@@ -166,8 +152,6 @@ function matchCommands(options, term) {
166
152
  let visible = true;
167
153
  let caption = '';
168
154
  try {
169
- // An item's accessors can throw if the command assumes a context (e.g.
170
- // an active notebook) the omnibox doesn't provide; skip those.
171
155
  label = item.label;
172
156
  visible = item.isVisible;
173
157
  caption = item.caption;
@@ -209,8 +193,6 @@ function matchCommands(options, term) {
209
193
  let visible = true;
210
194
  let caption = '';
211
195
  try {
212
- // A command's accessors can throw if they assume a context (e.g. an
213
- // active notebook) the omnibox doesn't provide; skip those.
214
196
  label = commands.label(id);
215
197
  visible = commands.isVisible(id);
216
198
  caption = commands.caption(id);
@@ -276,7 +258,7 @@ function buildAgentItems(commands, agents, prompt, trans) {
276
258
  const items = [];
277
259
  for (const agent of agents) {
278
260
  // Agents without `promptArgs` can't take an inline prompt (the launcher
279
- // would drop it), so they don't belong in an "Ask …" row.
261
+ // would drop it).
280
262
  if (agent.promptArgs === undefined) {
281
263
  continue;
282
264
  }
@@ -1,52 +1,50 @@
1
1
  import type { IStateDB } from '@jupyterlab/statedb';
2
2
  import type { ReadonlyPartialJSONObject } from '@lumino/coreutils';
3
- /**
4
- * Kinds of omnibox results whose uses are recorded.
5
- */
6
3
  export type RecentKind = 'command' | 'file';
7
4
  /**
8
5
  * A single recorded use: a command that was run or a file that was opened.
9
6
  */
10
7
  interface IRecentEntry {
8
+ /**
9
+ * Whether the entry records a command run or a file opened.
10
+ */
11
11
  kind: RecentKind;
12
12
  /**
13
13
  * The command id, or the workspace-relative file path.
14
14
  */
15
15
  id: string;
16
16
  /**
17
- * Arguments the command ran with, for palette-style entries whose label
18
- * and behavior depend on them (e.g. one "Use Theme: …" per theme).
17
+ * Arguments the command ran with, for palette-style entries whose label and
18
+ * behavior depend on them.
19
19
  */
20
20
  args?: ReadonlyPartialJSONObject;
21
21
  }
22
22
  /**
23
- * A most-recently-used list of omnibox results, generic over the result kind
24
- * so commands and files (and future kinds) share one store. Entries are kept
25
- * most-recent-first, capped at `maxItems` per kind, and persisted through the
26
- * state database so they survive reloads. Without a state database the list
27
- * still works for the lifetime of the page.
23
+ * A most-recently-used list of omnibox results, most-recent-first, capped at
24
+ * `maxItems` per kind and persisted through the state database. Without a
25
+ * state database it still works for the lifetime of the page.
28
26
  */
29
27
  export declare class OmniboxRecents {
30
28
  constructor(options?: OmniboxRecents.IOptions);
31
29
  /**
32
- * Maximum number of entries remembered per kind. Lowering it trims the list
33
- * immediately; `0` disables recents entirely.
30
+ * Maximum entries kept per kind; lowering trims immediately, `0` disables recents.
34
31
  */
35
32
  get maxItems(): number;
33
+ /**
34
+ * Set the maximum entries kept per kind.
35
+ */
36
36
  set maxItems(value: number);
37
37
  /**
38
- * The recorded entries, most recent first — all of them, or only those of
39
- * one kind.
38
+ * The recorded entries, most recent first, optionally filtered to one kind.
40
39
  */
41
40
  entries(kind?: RecentKind): IRecentEntry[];
42
41
  /**
43
- * Record a use of `id` (with the args it ran with, if any), moving it to
44
- * the front of its kind's list.
42
+ * Record a use, moving the entry to the front of its kind's list.
45
43
  */
46
44
  touch(kind: RecentKind, id: string, args?: ReadonlyPartialJSONObject): void;
47
45
  /**
48
46
  * Load the persisted list. Entries recorded before the load completes stay
49
- * at the front, ahead of the restored history.
47
+ * ahead of the restored history.
50
48
  */
51
49
  restore(): Promise<void>;
52
50
  /**