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
@@ -6,26 +6,16 @@ import { ITranslator, nullTranslator } from '@jupyterlab/translation';
6
6
  import { StateEffect, StateField } from '@codemirror/state';
7
7
  import { Decoration, EditorView } from '@codemirror/view';
8
8
  const PLUGIN_ID = 'xtralab:highlight';
9
- /**
10
- * Highlight a contiguous range of lines, or clear every highlight. These are
11
- * the only two commands the plugin contributes; both are designed to be driven
12
- * by a coding agent over the MCP command bridge to walk a user through code.
13
- */
14
9
  const HIGHLIGHT_LINES_COMMAND = 'xtralab:highlight-lines';
15
10
  const CLEAR_HIGHLIGHTS_COMMAND = 'xtralab:clear-highlights';
16
- /**
17
- * CodeMirror line-decoration class; styled in style/highlight.css.
18
- */
19
11
  const HIGHLIGHT_LINE_CLASS = 'jp-xtralab-highlightLine';
20
12
  /**
21
- * A CodeMirror effect carrying the 1-indexed, inclusive line range to
22
- * highlight, or `null` to clear the editor's highlights.
13
+ * Carries the 1-indexed inclusive line range to highlight, or `null` to clear.
23
14
  */
24
15
  const setHighlight = StateEffect.define();
25
16
  /**
26
- * Holds the highlight decorations for one editor. It is injected lazily (the
27
- * first time an editor is highlighted) via `StateEffect.appendConfig`, so
28
- * editors that are never highlighted pay nothing.
17
+ * Highlight decorations for one editor; injected lazily via
18
+ * `StateEffect.appendConfig` so editors never highlighted pay nothing.
29
19
  */
30
20
  const highlightField = StateField.define({
31
21
  create: () => Decoration.none,
@@ -54,11 +44,6 @@ const highlightField = StateField.define({
54
44
  },
55
45
  provide: field => EditorView.decorations.from(field)
56
46
  });
57
- /**
58
- * Return the CodeMirror view backing a widget's file editor, or `null` when
59
- * the widget is not a CodeMirror-based text editor (a notebook, a terminal,
60
- * the settings editor, …).
61
- */
62
47
  function viewForWidget(widget) {
63
48
  const content = widget === null || widget === void 0 ? void 0 : widget.content;
64
49
  return content instanceof FileEditor &&
@@ -66,25 +51,15 @@ function viewForWidget(widget) {
66
51
  ? content.editor.editor
67
52
  : null;
68
53
  }
69
- /**
70
- * Coerce a JSON command argument to a positive integer line number, falling
71
- * back to `fallback` when it is missing or not a finite number.
72
- */
73
54
  function toLine(value, fallback) {
74
55
  const n = Math.trunc(Number(value));
75
56
  return Number.isFinite(n) && n >= 1 ? n : fallback;
76
57
  }
77
58
  /**
78
- * Contribute `xtralab:highlight-lines` and `xtralab:clear-highlights`.
79
- *
80
- * The built-in command surface can open a file (`docmanager:open`) and move
81
- * the cursor to a line (`fileeditor:go-to-line`), but it cannot persistently
82
- * highlight a span of lines — `documentsearch:start` only marks text matches
83
- * and hijacks the find box. This plugin fills that gap with a CodeMirror line
84
- * decoration, so an agent can point at "lines 31–43 of src/index.ts" while it
85
- * narrates a walkthrough. `xtralab:highlight-lines` opens the file when needed,
86
- * scrolls the range into view, and replaces any previous highlight in that
87
- * editor; `xtralab:clear-highlights` removes every highlight.
59
+ * Contributes `xtralab:highlight-lines` and `xtralab:clear-highlights`,
60
+ * filling the persistent span-highlight gap in the core command surface
61
+ * (`documentsearch:start` only marks text matches and hijacks the find box)
62
+ * so an agent can point at lines while narrating a walkthrough.
88
63
  */
89
64
  const plugin = {
90
65
  id: PLUGIN_ID,
@@ -95,8 +70,6 @@ const plugin = {
95
70
  activate: (app, docManager, palette, translator) => {
96
71
  const { commands, shell } = app;
97
72
  const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('jupyterlab');
98
- // Editors that currently carry a highlight, so a single clear can reach
99
- // them all. Disposed editors are dropped on the next clear.
100
73
  const highlighted = new Set();
101
74
  const ensureField = (view) => {
102
75
  if (view.state.field(highlightField, false) === undefined) {
@@ -106,8 +79,7 @@ const plugin = {
106
79
  commands.addCommand(HIGHLIGHT_LINES_COMMAND, {
107
80
  label: trans.__('Highlight Lines'),
108
81
  caption: trans.__('Highlight a range of lines in a text editor'),
109
- // Advertise the argument shape so agents listing commands over the MCP
110
- // bridge can see how to call it, the same way core commands do.
82
+ // Advertise the argument shape to agents listing commands over the MCP bridge.
111
83
  describedBy: {
112
84
  args: {
113
85
  type: 'object',
@@ -136,9 +108,8 @@ const plugin = {
136
108
  const endLine = toLine(args['endLine'], line);
137
109
  const path = typeof args['path'] === 'string' ? args['path'] : undefined;
138
110
  const reveal = args['reveal'] !== false;
139
- // With a path, bind strictly to that document: never fall back to the
140
- // active widget, or an explicit path could silently highlight an
141
- // unrelated editor that happens to be focused.
111
+ // With a path, bind strictly to that document — falling back to the
112
+ // active widget could silently highlight an unrelated editor.
142
113
  let widget;
143
114
  if (path) {
144
115
  // Fail fast on a missing path instead of opening a phantom widget
@@ -153,7 +124,6 @@ const plugin = {
153
124
  if (!opened) {
154
125
  throw new Error(`xtralab: could not open "${path}"`);
155
126
  }
156
- // Wait for the model and the editor view to be ready.
157
127
  await opened.context.ready;
158
128
  await opened.revealed;
159
129
  widget = opened;
@@ -179,7 +149,6 @@ const plugin = {
179
149
  effects.push(EditorView.scrollIntoView(anchor, { y: 'center' }));
180
150
  }
181
151
  view.dispatch({ effects });
182
- // Forget editors that have since been closed before tracking this one.
183
152
  for (const tracked of highlighted) {
184
153
  if (!tracked.dom.isConnected) {
185
154
  highlighted.delete(tracked);
package/lib/index.d.ts CHANGED
@@ -1,12 +1,3 @@
1
1
  import { JupyterFrontEndPlugin } from '@jupyterlab/application';
2
- /**
3
- * Every plugin contributed by `xtralab`. The entry point of the
4
- * labextension is an array because the package bundles several independent
5
- * enhancements (file browser, git diff providers, …) — JupyterLab activates
6
- * each plugin individually and only the ones whose required tokens are
7
- * available end up running. `gitPlugins` and `launcherPlugins` are themselves
8
- * arrays (the git diff providers; the launcher plus its editor registry), so
9
- * they are spread in.
10
- */
11
2
  declare const plugins: JupyterFrontEndPlugin<unknown>[];
12
3
  export default plugins;
package/lib/index.js CHANGED
@@ -20,15 +20,6 @@ import terminalNotificationsPlugin from './terminalNotifications';
20
20
  import terminalsPlugin from './terminals';
21
21
  import topBarPlugin from './topBar';
22
22
  import walkthroughPlugin from './walkthrough';
23
- /**
24
- * Every plugin contributed by `xtralab`. The entry point of the
25
- * labextension is an array because the package bundles several independent
26
- * enhancements (file browser, git diff providers, …) — JupyterLab activates
27
- * each plugin individually and only the ones whose required tokens are
28
- * available end up running. `gitPlugins` and `launcherPlugins` are themselves
29
- * arrays (the git diff providers; the launcher plus its editor registry), so
30
- * they are spread in.
31
- */
32
23
  const plugins = [
33
24
  aboutPlugin,
34
25
  agentSessionsPlugin,
@@ -1,95 +1,99 @@
1
1
  import { LabIcon } from '@jupyterlab/ui-components';
2
2
  /**
3
- * The shape of an agent card on the launcher. The `command` is the literal
4
- * text typed into the new terminal session — interactive shells expand
5
- * aliases, so users can point at `claude`, `cl`, or whatever runs their
6
- * preferred wrapper.
3
+ * An agent card on the launcher. `command` is the literal text typed into the
4
+ * new terminal, so interactive-shell aliases resolve.
7
5
  */
8
6
  export interface IAgent {
7
+ /**
8
+ * Stable id; keys the settings merge and the per-agent launch command.
9
+ */
9
10
  id: string;
11
+ /**
12
+ * Card label, e.g. "Claude".
13
+ */
10
14
  label: string;
15
+ /**
16
+ * Card tooltip; also the palette command caption.
17
+ */
11
18
  caption: string;
19
+ /**
20
+ * The literal command typed into the new terminal.
21
+ */
12
22
  command: string;
23
+ /**
24
+ * Brand icon for the card.
25
+ */
13
26
  icon: LabIcon;
27
+ /**
28
+ * Sort position among the launcher's agent cards.
29
+ */
14
30
  rank: number;
15
31
  /**
16
- * When false, the launcher skips the `which`-based availability check for
17
- * this entry — useful for aliases or shell functions that aren't on PATH
18
- * but still resolve when typed in a real terminal. Defaults to true.
32
+ * When false, skip the `which`-based availability check — for aliases or
33
+ * shell functions not on PATH. Defaults to true.
19
34
  */
20
35
  requireAvailable: boolean;
21
36
  /**
22
- * Argv tokens spliced between `command` and a shell-quoted prompt when
23
- * the user types one into the launcher's prompt box. The semantics:
24
- *
25
- * - `[]` → prompt is appended as a positional argument:
26
- * `<command> 'PROMPT'`. (Used by claude, codex, vibe, pi.)
27
- * - `['-i']` / `['--prompt']` → the prompt is preceded by a flag:
28
- * `<command> -i 'PROMPT'`. (Used by copilot, opencode.)
29
- * - `undefined` → the agent does not accept an initial prompt. The
30
- * launcher dims the agent's button while the prompt textarea is
31
- * non-empty, so the user gets a clear signal rather than a silently
32
- * dropped prompt.
33
- *
34
- * The prompt itself is always single-quoted with embedded single quotes
35
- * escaped, so multi-line prompts and shell metacharacters are safe.
37
+ * Argv tokens spliced between `command` and the shell-quoted prompt:
38
+ * `[]` appends the prompt positionally, `['-i']` prefixes a flag, and
39
+ * `undefined` means no prompt support (the launcher dims the button).
36
40
  */
37
41
  promptArgs?: string[];
38
42
  }
39
43
  /**
40
- * The settings-side shape: every field except `id` is optional, so a user
41
- * can override a single field on a default agent (e.g. swap the command for
42
- * an alias) without restating the whole entry. New ids define brand-new
43
- * agent cards.
44
+ * The settings-side shape: every field except `id` is optional so a user can
45
+ * override a single field on a default agent; new ids define new agent cards.
44
46
  */
45
47
  export interface IAgentSettings {
48
+ /**
49
+ * Id of the agent to override; a new id defines a new card.
50
+ */
46
51
  id: string;
52
+ /**
53
+ * See `IAgent.label`.
54
+ */
47
55
  label?: string;
56
+ /**
57
+ * See `IAgent.caption`.
58
+ */
48
59
  caption?: string;
60
+ /**
61
+ * See `IAgent.command`.
62
+ */
49
63
  command?: string;
50
64
  /**
51
- * Inline SVG for a custom agent's icon. Required for new ids whose icon
52
- * isn't shipped with xtralab; ignored for default ids unless explicitly
53
- * set (in which case it overrides the built-in).
65
+ * Inline SVG icon. Required for new ids; overrides the built-in when set on
66
+ * a default id.
54
67
  */
55
68
  iconSvg?: string;
69
+ /**
70
+ * See `IAgent.rank`.
71
+ */
56
72
  rank?: number;
57
73
  /**
58
- * When false, the agent is hidden from the launcher and the command
59
- * palette. Defaults to true.
74
+ * When false, hides the agent from the launcher and the command palette.
60
75
  */
61
76
  enabled?: boolean;
62
77
  /**
63
- * See `IAgent.requireAvailable`. Defaults to true for a built-in agent that
64
- * still uses its shipped command, and to false once you override the
65
- * `command` (a user-chosen command — often a shell alias — is trusted and
66
- * always shown). Set it explicitly to force the check on or off.
78
+ * See `IAgent.requireAvailable`. Defaults to true, but flips to false once
79
+ * `command` is overridden (a user-chosen alias is trusted).
67
80
  */
68
81
  requireAvailable?: boolean;
69
82
  /**
70
- * See `IAgent.promptArgs`. Pass an empty array to mark the agent as
71
- * accepting a positional prompt; pass an array like `["-p"]` to use a
72
- * flag. Pass `null` to explicitly turn off prompt support for an agent
73
- * that has it on by default.
83
+ * See `IAgent.promptArgs`. `null` explicitly turns off an agent's default
84
+ * prompt support.
74
85
  */
75
86
  promptArgs?: string[] | null;
76
87
  }
77
88
  /**
78
- * The built-in agents projected into the JSON settings shape
79
- * ({@link IAgentSettings}), dropping the runtime-only {@link LabIcon}.
80
- * {@link registerLauncherSchemaDefaults} injects this as the `agents` setting's
81
- * schema default so the Settings Editor shows the shipped list.
89
+ * The built-in agents projected into the settings shape (no runtime LabIcon),
90
+ * injected as the `agents` schema default so the Settings Editor shows them.
82
91
  */
83
92
  export declare function defaultAgentSettings(): IAgentSettings[];
84
93
  /**
85
- * Merge xtralab's defaults with the user's settings. Default entries keep
86
- * their built-in fields unless explicitly overridden; user-only entries are
87
- * appended. `enabled: false` filters an entry out of the result entirely
88
- * (so callers don't need to check the flag again).
89
- *
90
- * Overriding a built-in agent's `command` also turns its `requireAvailable`
91
- * off, so the card survives the launcher's `which`-based availability filter
92
- * even when the new command is a shell alias the server can't resolve. See the
93
- * built-in branch below for the rationale.
94
+ * Merge xtralab's defaults with the user's settings: defaults keep their
95
+ * fields unless overridden, user-only ids are appended, and `enabled: false`
96
+ * removes an entry entirely. Overriding a built-in's `command` also turns
97
+ * `requireAvailable` off so an aliased command survives the `which` filter.
94
98
  */
95
99
  export declare function mergeAgents(overrides: IAgentSettings[]): IAgent[];
@@ -1,15 +1,10 @@
1
1
  import { LabIcon, terminalIcon } from '@jupyterlab/ui-components';
2
2
  import { BUILTIN_AGENT_ICONS } from './icons';
3
3
  /**
4
- * Default agent cards shipped with xtralab. Seven of these (Claude, Codex,
5
- * Copilot, Goose, OpenCode, Kiro, Mistral Vibe) mirror first-class personas
6
- * in `jupyter-ai-contrib/jupyter-ai-acp-client` (which is also where their
7
- * icons come from), but use the bare CLI names a user would type in a
8
- * terminal rather than the ACP wrapper binaries that project spawns.
9
- * Antigravity (Google's agent-first IDE/CLI, `agy`) is the Google agent.
10
- * Pi (https://pi.dev, `earendil-works/pi`) is a minimal extensible coding
11
- * agent; its mark comes straight from its site. Anything not on the user's
12
- * `$PATH` is filtered out at activation time, so the wider list is harmless.
4
+ * Default agent cards. Most mirror `jupyter-ai-contrib/jupyter-ai-acp-client`
5
+ * personas but use the bare CLI names a user would type, not the ACP wrappers.
6
+ * Anything not on `$PATH` is filtered out at activation, so the wide list is
7
+ * harmless.
13
8
  */
14
9
  const DEFAULTS = [
15
10
  {
@@ -40,13 +35,8 @@ const DEFAULTS = [
40
35
  icon: BUILTIN_AGENT_ICONS.antigravity,
41
36
  rank: 2,
42
37
  requireAvailable: true
43
- // `agy` is the Antigravity launcher binary — a VS Code-derived editor
44
- // CLI that opens the Agent Manager / workspace, not a terminal REPL.
45
- // Its positional args are file/folder paths, so there is no inline
46
- // natural-language prompt form; like goose/kiro we omit promptArgs so a
47
- // typed prompt dims the button instead of being mangled into a path.
48
- // The command stays the bare binary (no `agy .`) so the server-side
49
- // `shutil.which` availability check still resolves it.
38
+ // `agy` opens the Antigravity editor; its positional args are paths, not
39
+ // prompts, and the bare binary keeps the server-side `which` check working.
50
40
  },
51
41
  {
52
42
  id: 'copilot',
@@ -56,8 +46,7 @@ const DEFAULTS = [
56
46
  icon: BUILTIN_AGENT_ICONS.copilot,
57
47
  rank: 3,
58
48
  requireAvailable: true,
59
- // `-i "PROMPT"` is the documented way to start interactive mode and
60
- // auto-execute the prompt; `-p` exits after responding (non-interactive).
49
+ // `-i` starts interactive mode with the prompt; `-p` exits after responding.
61
50
  promptArgs: ['-i']
62
51
  },
63
52
  {
@@ -68,8 +57,7 @@ const DEFAULTS = [
68
57
  icon: BUILTIN_AGENT_ICONS.goose,
69
58
  rank: 4,
70
59
  requireAvailable: true
71
- // `goose` does not accept an inline interactive prompt; users would
72
- // need to type the prompt after `goose session` starts.
60
+ // `goose` takes no inline prompt; it must be typed after `goose session`.
73
61
  },
74
62
  {
75
63
  id: 'opencode',
@@ -89,8 +77,7 @@ const DEFAULTS = [
89
77
  icon: BUILTIN_AGENT_ICONS.kiro,
90
78
  rank: 6,
91
79
  requireAvailable: true
92
- // The Kiro chat session only takes initial prompts via the in-session
93
- // `/chat new <prompt>` slash command, not a CLI argument.
80
+ // Kiro only takes initial prompts via the in-session `/chat new` command.
94
81
  },
95
82
  {
96
83
  id: 'mistral-vibe',
@@ -110,16 +97,12 @@ const DEFAULTS = [
110
97
  icon: BUILTIN_AGENT_ICONS.pi,
111
98
  rank: 8,
112
99
  requireAvailable: true,
113
- // `pi [messages...]` starts the interactive TUI and sends the messages
114
- // as the first user prompt, so the positional form applies.
115
100
  promptArgs: []
116
101
  }
117
102
  ];
118
103
  /**
119
- * The built-in agents projected into the JSON settings shape
120
- * ({@link IAgentSettings}), dropping the runtime-only {@link LabIcon}.
121
- * {@link registerLauncherSchemaDefaults} injects this as the `agents` setting's
122
- * schema default so the Settings Editor shows the shipped list.
104
+ * The built-in agents projected into the settings shape (no runtime LabIcon),
105
+ * injected as the `agents` schema default so the Settings Editor shows them.
123
106
  */
124
107
  export function defaultAgentSettings() {
125
108
  return DEFAULTS.map(agent => {
@@ -131,8 +114,6 @@ export function defaultAgentSettings() {
131
114
  rank: agent.rank,
132
115
  requireAvailable: agent.requireAvailable
133
116
  };
134
- // Omit `promptArgs` for agents that don't take an inline prompt, so the
135
- // default doesn't show a prompt form they lack.
136
117
  if (agent.promptArgs !== undefined) {
137
118
  entry.promptArgs = agent.promptArgs;
138
119
  }
@@ -147,15 +128,10 @@ function resolveIcon(id, iconSvg) {
147
128
  return (_a = BUILTIN_AGENT_ICONS[id]) !== null && _a !== void 0 ? _a : terminalIcon;
148
129
  }
149
130
  /**
150
- * Merge xtralab's defaults with the user's settings. Default entries keep
151
- * their built-in fields unless explicitly overridden; user-only entries are
152
- * appended. `enabled: false` filters an entry out of the result entirely
153
- * (so callers don't need to check the flag again).
154
- *
155
- * Overriding a built-in agent's `command` also turns its `requireAvailable`
156
- * off, so the card survives the launcher's `which`-based availability filter
157
- * even when the new command is a shell alias the server can't resolve. See the
158
- * built-in branch below for the rationale.
131
+ * Merge xtralab's defaults with the user's settings: defaults keep their
132
+ * fields unless overridden, user-only ids are appended, and `enabled: false`
133
+ * removes an entry entirely. Overriding a built-in's `command` also turns
134
+ * `requireAvailable` off so an aliased command survives the `which` filter.
159
135
  */
160
136
  export function mergeAgents(overrides) {
161
137
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
@@ -181,32 +157,14 @@ export function mergeAgents(overrides) {
181
157
  ? resolveIcon(base.id, override.iconSvg)
182
158
  : base.icon,
183
159
  rank: (_d = override.rank) !== null && _d !== void 0 ? _d : base.rank,
184
- // The availability filter exists to prune xtralab's *built-in* command
185
- // from the launcher when it isn't installed. Once the user points the
186
- // agent at their own command — e.g. the `ccm` alias wrapping `claude
187
- // --effort=max …` — the server's `shutil.which` probe can't see it
188
- // (aliases and shell functions only exist inside an interactive shell),
189
- // so keeping the check on would wrongly hide the card. We therefore only
190
- // require availability while the command is still xtralab's default; a
191
- // user-chosen command is trusted and always shown. An explicit
192
- // `requireAvailable` still applies to the unchanged default command, so a
193
- // user can alias `claude` itself and set `requireAvailable: false` (or
194
- // force the check back on).
195
160
  requireAvailable: command === base.command
196
161
  ? ((_e = override.requireAvailable) !== null && _e !== void 0 ? _e : base.requireAvailable)
197
162
  : false,
198
- // `null` is the explicit way to opt out of an agent's default prompt
199
- // support; an absent key keeps the default. `undefined` from `??` is
200
- // pruned below.
201
163
  promptArgs: override.promptArgs === null
202
164
  ? undefined
203
165
  : ((_f = override.promptArgs) !== null && _f !== void 0 ? _f : base.promptArgs)
204
166
  });
205
167
  }
206
- // What remains in `overrideById` are entries with ids that don't match a
207
- // default — treat them as new agents the user is adding. Skip silently
208
- // when a required field is missing rather than throwing; the settings
209
- // schema validates the shape, so this is just a defensive fallback.
210
168
  let nextRank = merged.reduce((max, agent) => Math.max(max, agent.rank), -1) + 1;
211
169
  for (const entry of overrideById.values()) {
212
170
  if (entry.enabled === false) {
@@ -1,12 +1,6 @@
1
1
  /**
2
- * Hit the xtralab server extension's `which`-proxy endpoint and turn the
3
- * response into a Set of commands that resolved to a real binary on the
4
- * server's `$PATH`. The frontend uses this set to filter the launcher's
5
- * agent cards.
6
- *
7
- * On any failure (server extension not loaded, network error, malformed
8
- * response) the returned Set is `null` — callers should treat that as
9
- * "availability unknown" and either fall back to showing all agents or
10
- * surface the error, depending on context.
2
+ * Ask the server extension's `which`-proxy endpoint which commands resolve on
3
+ * its `$PATH`. Returns `null` on any failure — callers should treat that as
4
+ * "availability unknown", not as "nothing available".
11
5
  */
12
6
  export declare function fetchAvailableCommands(commands: string[]): Promise<Set<string> | null>;
@@ -1,15 +1,9 @@
1
1
  import { URLExt } from '@jupyterlab/coreutils';
2
2
  import { ServerConnection } from '@jupyterlab/services';
3
3
  /**
4
- * Hit the xtralab server extension's `which`-proxy endpoint and turn the
5
- * response into a Set of commands that resolved to a real binary on the
6
- * server's `$PATH`. The frontend uses this set to filter the launcher's
7
- * agent cards.
8
- *
9
- * On any failure (server extension not loaded, network error, malformed
10
- * response) the returned Set is `null` — callers should treat that as
11
- * "availability unknown" and either fall back to showing all agents or
12
- * surface the error, depending on context.
4
+ * Ask the server extension's `which`-proxy endpoint which commands resolve on
5
+ * its `$PATH`. Returns `null` on any failure — callers should treat that as
6
+ * "availability unknown", not as "nothing available".
13
7
  */
14
8
  export async function fetchAvailableCommands(commands) {
15
9
  if (commands.length === 0) {
@@ -5,48 +5,23 @@ import type { CommandRegistry } from '@lumino/commands';
5
5
  import { type IDisposable } from '@lumino/disposable';
6
6
  import type { IAgentSessions } from '../agentSessions';
7
7
  import type { IAgent } from './agents';
8
- /**
9
- * The command id for opening the launcher.
10
- */
11
8
  export declare const CREATE_LAUNCHER_COMMAND = "launcher:create";
12
9
  /**
13
- * Register a JupyterLab command per agent. Each command opens a new
14
- * terminal via `terminal:create-new` and feeds the agent's shell command
15
- * into the fresh session as if the user had typed it.
16
- *
17
- * Returns a single disposable that tears down every registered command —
18
- * the launcher disposes the previous set before re-registering on settings
19
- * changes so the command palette stays in sync with the configured agents.
20
- *
21
- * When an `agentSessions` registry is supplied, each launch tags its terminal
22
- * session with the agent's command, so the terminals panel can badge the row
23
- * with the agent's logo immediately (before server-side detection confirms
24
- * it).
10
+ * Register a JupyterLab command per agent that opens a new terminal and types
11
+ * the agent's shell command into it. Returns one disposable tearing down every
12
+ * command, so a settings change can re-register without stale palette entries.
13
+ * `agentSessions`, when given, launch-tags each session for the terminals panel.
25
14
  */
26
15
  export declare function registerAgentCommands(app: JupyterFrontEnd, agents: IAgent[], agentSessions?: IAgentSessions | null): IDisposable;
27
16
  /**
28
17
  * Open a fresh terminal, type `invocation` into it as if the user had, and
29
- * label the tab. Shared by the per-agent launch commands and the launcher's
30
- * editor tile so the fiddly "wait for the websocket, then write stdin"
31
- * sequence lives in one place.
32
- *
33
- * `onSession`, when given, is called once with the new session's name right
34
- * after the terminal is revealed. Callers use it to optimistically tag the
35
- * session so the terminals panel can badge it with the agent's (or editor's)
36
- * logo before server-side detection confirms the running process.
37
- *
38
- * Resolves with the host `MainAreaWidget` so the caller can place it — the
39
- * launcher swaps it into its own tab.
18
+ * label the tab. `onSession` receives the new session's name so callers can
19
+ * launch-tag it for the terminals panel. Resolves with the host
20
+ * `MainAreaWidget` so the caller can place it.
40
21
  */
41
22
  export declare function launchInTerminal(commands: CommandRegistry, options: {
42
23
  cwd?: string;
43
- /**
44
- * The literal command line typed into the fresh terminal.
45
- */
46
24
  invocation: string;
47
- /**
48
- * Tab/title label applied once the command is sent.
49
- */
50
25
  label: string;
51
26
  onSession?: (sessionName: string) => void;
52
27
  }): Promise<MainAreaWidget<ITerminal.ITerminal>>;
@@ -1,23 +1,12 @@
1
1
  import { DisposableSet } from '@lumino/disposable';
2
2
  import { buildAgentInvocation } from './invocation';
3
3
  import { agentCommandId } from './tokens';
4
- /**
5
- * The command id for opening the launcher.
6
- */
7
4
  export const CREATE_LAUNCHER_COMMAND = 'launcher:create';
8
5
  /**
9
- * Register a JupyterLab command per agent. Each command opens a new
10
- * terminal via `terminal:create-new` and feeds the agent's shell command
11
- * into the fresh session as if the user had typed it.
12
- *
13
- * Returns a single disposable that tears down every registered command —
14
- * the launcher disposes the previous set before re-registering on settings
15
- * changes so the command palette stays in sync with the configured agents.
16
- *
17
- * When an `agentSessions` registry is supplied, each launch tags its terminal
18
- * session with the agent's command, so the terminals panel can badge the row
19
- * with the agent's logo immediately (before server-side detection confirms
20
- * it).
6
+ * Register a JupyterLab command per agent that opens a new terminal and types
7
+ * the agent's shell command into it. Returns one disposable tearing down every
8
+ * command, so a settings change can re-register without stale palette entries.
9
+ * `agentSessions`, when given, launch-tags each session for the terminals panel.
21
10
  */
22
11
  export function registerAgentCommands(app, agents, agentSessions = null) {
23
12
  const disposables = new DisposableSet();
@@ -35,9 +24,7 @@ export function registerAgentCommands(app, agents, agentSessions = null) {
35
24
  cwd,
36
25
  invocation,
37
26
  label: agent.label,
38
- // Optimistically tag the session with this agent so the terminals
39
- // panel can show its logo right away; server-side detection takes
40
- // over as the source of truth on its next poll.
27
+ // Optimistic tag; server-side detection takes over on its next poll.
41
28
  onSession: name => agentSessions === null || agentSessions === void 0 ? void 0 : agentSessions.set(name, agent.command)
42
29
  });
43
30
  }
@@ -48,27 +35,17 @@ export function registerAgentCommands(app, agents, agentSessions = null) {
48
35
  }
49
36
  /**
50
37
  * Open a fresh terminal, type `invocation` into it as if the user had, and
51
- * label the tab. Shared by the per-agent launch commands and the launcher's
52
- * editor tile so the fiddly "wait for the websocket, then write stdin"
53
- * sequence lives in one place.
54
- *
55
- * `onSession`, when given, is called once with the new session's name right
56
- * after the terminal is revealed. Callers use it to optimistically tag the
57
- * session so the terminals panel can badge it with the agent's (or editor's)
58
- * logo before server-side detection confirms the running process.
59
- *
60
- * Resolves with the host `MainAreaWidget` so the caller can place it — the
61
- * launcher swaps it into its own tab.
38
+ * label the tab. `onSession` receives the new session's name so callers can
39
+ * launch-tag it for the terminals panel. Resolves with the host
40
+ * `MainAreaWidget` so the caller can place it.
62
41
  */
63
42
  export async function launchInTerminal(commands, options) {
64
43
  const { cwd, invocation, label, onSession } = options;
65
44
  const main = (await commands.execute('terminal:create-new', {
66
45
  cwd
67
46
  }));
68
- // `MainAreaWidget.revealed` chains off the `reveal` promise the terminal
69
- // extension passes in (the xterm.js widget's own `ready` promise), so
70
- // awaiting it guarantees the Terminal widget has finished its constructor
71
- // and connected its session listeners.
47
+ // `revealed` chains off the terminal's `ready` promise, so awaiting it
48
+ // guarantees the widget finished construction and connected its listeners.
72
49
  await main.revealed;
73
50
  const session = main.content.session;
74
51
  onSession === null || onSession === void 0 ? void 0 : onSession(session.name);
@@ -83,20 +60,12 @@ export async function launchInTerminal(commands, options) {
83
60
  type: 'stdin',
84
61
  content: [invocation + '\r']
85
62
  });
86
- // Give the tab and the status-bar list a meaningful default label. The
87
- // XTerm widget's `_initialConnection` listener overwrites the title with
88
- // `Terminal {N}` when the WebSocket first reports `connected`; we connect
89
- // *after* that listener (and call `applyLabel` after `sendCommand`), so by
90
- // the time we run the upstream listener has already had its turn. Programs
91
- // that publish a real xterm title escape sequence still win —
92
- // `XTerm.onTitleChange` resets the label whenever it fires.
63
+ // XTerm's `_initialConnection` resets the title on first connect; we run
64
+ // after it, so this label survives. A title escape still wins (`onTitleChange`).
93
65
  applyLabel();
94
66
  };
95
- // Match how the Terminal widget itself sends its `initialCommand`: either
96
- // fire immediately if the session is already connected, or wait for the next
97
- // `connectionStatusChanged` that flips it to `connected`. Without this the
98
- // stdin write races the websocket handshake and the command silently
99
- // disappears.
67
+ // Without waiting for `connected` the stdin write races the websocket
68
+ // handshake and the command silently disappears.
100
69
  if (session.connectionStatus === 'connected') {
101
70
  sendCommand();
102
71
  }