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
@@ -12,16 +12,13 @@ export interface IAgentTerminalSession {
12
12
  name: string;
13
13
 
14
14
  /**
15
- * The agent identifier server-side detection reported for the session:
16
- * the configured `command`, or the canonical agent `id` when the command
17
- * is an alias (e.g. `ccm` spawning `claude`). Matches an `IAgent` by
18
- * either field.
15
+ * The agent identifier detection reported: the configured `command`, or the
16
+ * canonical `id` when the command is an alias (e.g. `ccm` spawning `claude`).
19
17
  */
20
18
  command: string;
21
19
 
22
20
  /**
23
- * Display label — the session's real title (the launcher's agent name, or
24
- * whatever the running program published via an xterm escape sequence).
21
+ * Display label — the session's real (program-published) title.
25
22
  */
26
23
  label: string;
27
24
 
@@ -35,12 +32,9 @@ export interface IAgentTerminalSession {
35
32
  /**
36
33
  * Running agent terminals, and a way to send a prompt into one.
37
34
  *
38
- * `sessions` only lists sessions where server-side process detection has
39
- * *confirmed* a running coding agent (editors and plain shells are excluded,
40
- * as are optimistic just-launched tags): every listed session is one whose
41
- * TUI can meaningfully receive pasted prompt text. `sendPrompt` re-validates
42
- * against the server before writing, since pasting prose into a shell prompt
43
- * would execute it.
35
+ * Only sessions with a detection-*confirmed* running agent are listed — never
36
+ * optimistic launch tags: pasted prompt text must land in an agent's TUI, not
37
+ * a shell prompt where it would be executed.
44
38
  */
45
39
  export interface IAgentTerminals {
46
40
  /**
@@ -54,22 +48,17 @@ export interface IAgentTerminals {
54
48
  readonly changed: ISignal<IAgentTerminals, void>;
55
49
 
56
50
  /**
57
- * Paste `prompt` into the named session's terminal and press Enter.
58
- *
59
- * Delivery is deliberately background: the text is written straight to
60
- * the session's websocket, bracketed-paste-wrapped so a multi-line prompt
61
- * arrives as one block in the agent's input box, without revealing or
62
- * focusing the terminal's tab — the user keeps working where they are,
63
- * and the agent CLIs queue the prompt themselves when they are busy.
64
- * Rejects when the session is gone or no agent is running in it anymore.
51
+ * Paste `prompt` (bracketed-paste-wrapped) into the named session and press
52
+ * Enter, writing straight to its websocket without revealing or focusing
53
+ * its tab. Rejects when the session is gone or no agent runs in it anymore.
65
54
  */
66
55
  sendPrompt(name: string, prompt: string): Promise<void>;
67
56
  }
68
57
 
69
58
  /**
70
59
  * DI token for {@link IAgentTerminals}. Provided by `xtralab:terminals`;
71
- * consumed — optionally, so each side works without the other — by
72
- * `xtralab:ask-agent` to offer running agent terminals as prompt targets.
60
+ * consumed optionally by `xtralab:ask-agent`, so each side works without
61
+ * the other.
73
62
  */
74
63
  export const IAgentTerminals = new Token<IAgentTerminals>(
75
64
  'xtralab:IAgentTerminals',
@@ -25,15 +25,10 @@ import * as React from 'react';
25
25
 
26
26
  import { SessionRegistry } from './model';
27
27
 
28
- /**
29
- * Id of the panel widget. Used for layout restoration and as the handle
30
- * the sidebar visibility toggle would target.
31
- */
32
28
  const RUNNING_TERMINALS_ID = 'xtralab-running-terminals';
33
29
 
34
30
  /**
35
- * Id of the accordion section holding the terminals list. Persisted by the
36
- * movable-sections plugin, so it must stay stable across releases.
31
+ * Persisted by the movable-sections plugin — must stay stable across releases.
37
32
  */
38
33
  const TERMINALS_SECTION_ID = 'xtralab-terminals-section';
39
34
 
@@ -75,8 +70,6 @@ export class RunningTerminals
75
70
  const newTerminal = new ToolbarButton({
76
71
  icon: addIcon,
77
72
  onClick: () => {
78
- // Anchor whatever the plugin shows (usually an agent menu) to the
79
- // button's bottom-left, in the viewport coordinates `Menu.open` wants.
80
73
  const rect = newTerminal.node.getBoundingClientRect();
81
74
  options.onCreate({ x: rect.left, y: rect.bottom });
82
75
  },
@@ -97,23 +90,39 @@ export class RunningTerminals
97
90
  this.addWidget(section);
98
91
  }
99
92
 
93
+ /**
94
+ * The accordion panel hosting the sections; read by the move plugin.
95
+ */
100
96
  get accordionPanel(): AccordionPanel {
101
97
  return this.content as AccordionPanel;
102
98
  }
103
99
 
100
+ /**
101
+ * A signal emitted when a section is announced to the move plugin.
102
+ */
104
103
  get sectionAdded(): ISignal<this, ISectionEntry> {
105
104
  return this._sectionAdded;
106
105
  }
107
106
 
107
+ /**
108
+ * The hosted section widgets, excluding the panel's own Terminals section.
109
+ */
108
110
  get sections(): ReadonlyArray<Widget> {
109
111
  return this.accordionPanel.widgets.filter(w => w !== this._section);
110
112
  }
111
113
 
114
+ /**
115
+ * Get the movable sections: just the Terminals section, while attached here.
116
+ */
112
117
  getSections(): ReadonlyArray<ISectionEntry> {
113
118
  const entry = this._sectionEntry();
114
119
  return entry ? [entry] : [];
115
120
  }
116
121
 
122
+ /**
123
+ * Detach the Terminals section for the move plugin and return it; `null`
124
+ * for an unknown id or when the section is already hosted elsewhere.
125
+ */
117
126
  removeSectionById(sectionId: string): Widget | null {
118
127
  if (
119
128
  sectionId !== TERMINALS_SECTION_ID ||
@@ -125,14 +134,23 @@ export class RunningTerminals
125
134
  return this._section;
126
135
  }
127
136
 
137
+ /**
138
+ * Re-attach the Terminals section after it moves back to this panel.
139
+ */
128
140
  reinsertSection(widget: Widget): void {
129
141
  this.addWidget(widget);
130
142
  }
131
143
 
144
+ /**
145
+ * Host a section moved in from another sidebar panel.
146
+ */
132
147
  addSection(widget: Widget): void {
133
148
  this.addWidget(widget);
134
149
  }
135
150
 
151
+ /**
152
+ * Detach a hosted section when it moves back to its own panel.
153
+ */
136
154
  removeSectionWidget(widget: Widget): void {
137
155
  if (widget.parent === this.content) {
138
156
  widget.parent = null;
@@ -162,12 +180,14 @@ export class RunningTerminals
162
180
  }
163
181
  }
164
182
 
183
+ /**
184
+ * Dispose of the panel and the registry it owns.
185
+ */
165
186
  dispose(): void {
166
187
  if (this.isDisposed) {
167
188
  return;
168
189
  }
169
- // The panel owns the registry, so tear down its upstream
170
- // subscriptions before the React tree goes away.
190
+ // The panel owns the registry; tear down its subscriptions first.
171
191
  this._registry.dispose();
172
192
  super.dispose();
173
193
  }
@@ -192,19 +212,25 @@ export class RunningTerminals
192
212
  }
193
213
 
194
214
  export namespace RunningTerminals {
215
+ /**
216
+ * The instantiation options for a {@link RunningTerminals} panel.
217
+ */
195
218
  export interface IOptions {
219
+ /**
220
+ * The session registry the panel renders and takes ownership of.
221
+ */
196
222
  registry: SessionRegistry;
223
+ /**
224
+ * The translation bundle for the panel's labels; untranslated if omitted.
225
+ */
197
226
  trans?: TranslationBundle;
198
227
  /**
199
- * Resolve the running-agent command for a row (from
200
- * `registry.agentCommandFor`) to the icon to show before its label —
201
- * the agent's logo, or the plain terminal icon. Supplied by the plugin
202
- * so the widget never imports the agent list.
228
+ * Resolve a row's running-agent command to its icon; supplied by the
229
+ * plugin so the widget never imports the agent list.
203
230
  */
204
231
  iconForCommand: (command: string | null) => LabIcon;
205
232
  /**
206
- * Activate the named session's open tab, or reopen it in a fresh
207
- * terminal widget if no tab is currently attached.
233
+ * Activate the named session's open tab, or reopen it in a fresh widget.
208
234
  */
209
235
  onActivate: (sessionName: string) => void;
210
236
  /**
@@ -212,16 +238,12 @@ export namespace RunningTerminals {
212
238
  */
213
239
  onShutdown: (sessionName: string) => void;
214
240
  /**
215
- * Shut down every running terminal at once. The plugin is expected to
216
- * confirm with the user first, since it tears down all live sessions.
241
+ * Shut down every running terminal; the plugin confirms with the user first.
217
242
  */
218
243
  onShutdownAll: () => void;
219
244
  /**
220
- * Activate the "+" button, anchored at the given viewport coordinates
221
- * (the bottom-left of the button). The plugin decides what to show
222
- * there — a menu of agents plus a plain terminal, or just a new
223
- * terminal when no agents are available — so the panel only reports
224
- * where the button is and never imports the command/menu machinery.
245
+ * Handle the "+" button, anchored at its bottom-left in viewport
246
+ * coordinates; the plugin decides what to show there.
225
247
  */
226
248
  onCreate: (anchor: { x: number; y: number }) => void;
227
249
  }
@@ -243,6 +265,9 @@ class TerminalsListing extends ReactWidget {
243
265
  this.addClass('jp-xtralab-Terminals-listing');
244
266
  }
245
267
 
268
+ /**
269
+ * Render the listing, re-rendering on every registry state change.
270
+ */
246
271
  protected render(): React.ReactElement {
247
272
  return (
248
273
  <UseSignal signal={this._options.registry.stateChanged}>
@@ -277,9 +302,6 @@ function RunningTerminalsComponent(props: {
277
302
  }): React.ReactElement {
278
303
  const { registry, trans, iconForCommand, onActivate, onShutdown } = props;
279
304
  const names = registry.sessionNames();
280
- // The session whose terminal is the current widget in the main area, so its
281
- // row can be highlighted. `null` when the current tab is a notebook or any
282
- // other non-terminal widget.
283
305
  const currentName = registry.currentSessionName();
284
306
 
285
307
  return (
@@ -296,15 +318,10 @@ function RunningTerminalsComponent(props: {
296
318
  const tooltip = hasWidget
297
319
  ? trans.__('Activate %1', label)
298
320
  : trans.__('Reopen %1', label);
299
- // The running agent's logo (e.g. Claude), or the plain terminal
300
- // icon when nothing recognised is running in the session.
301
321
  const RowIcon = iconForCommand(
302
322
  registry.agentCommandFor(name)
303
323
  ).react;
304
324
  const isCurrent = name === currentName;
305
- // The latest line of output from the session's agent, shown as a
306
- // smaller line under the title; `null` for rows with nothing to
307
- // surface (no agent running, or no open tab to read a live buffer).
308
325
  const activity = registry.activityFor(name);
309
326
  return (
310
327
  <li
@@ -1,14 +1,9 @@
1
1
  import { LabIcon } from '@jupyterlab/ui-components';
2
2
 
3
3
  /**
4
- * Mirror-symmetric "toggle sidebar" marks for the top-bar buttons, in the
5
- * same visual language as the macOS / VS Code / svgrepo sidebar icons
6
- * (https://www.svgrepo.com/vectors/sidebar/): a rounded window outline split
7
- * by a divider, with the controlled side shaded so left vs. right reads at a
8
- * glance. The artwork is hand-authored from basic geometry (rounded rect +
9
- * divider + a shaded panel) so there is no third-party licensing to track,
10
- * and every stroke/fill uses `currentColor` so the icons inherit the top
11
- * bar's text color across the light and dark themes.
4
+ * Mirror-symmetric "toggle sidebar" marks in the macOS / VS Code visual
5
+ * language. Hand-authored from basic geometry (no third-party licensing);
6
+ * every stroke/fill uses `currentColor` to follow the top bar's text color.
12
7
  */
13
8
 
14
9
  export const leftSidebarIcon = new LabIcon({
@@ -10,16 +10,12 @@ import { leftSidebarIcon, rightSidebarIcon } from './icons';
10
10
 
11
11
  const PLUGIN_ID = 'xtralab:top-bar';
12
12
 
13
- /**
14
- * Upstream commands from `@jupyterlab/application-extension` that collapse or
15
- * expand the side areas. We bind the buttons to these rather than
16
- * reimplementing the toggle, so behavior (and the `isToggled`/`isEnabled`
17
- * state the buttons reflect) stays in lockstep with the View menu entries
18
- * and their keyboard shortcuts.
19
- */
20
13
  const TOGGLE_LEFT_AREA = 'application:toggle-left-area';
21
14
  const TOGGLE_RIGHT_AREA = 'application:toggle-right-area';
22
15
 
16
+ /**
17
+ * A specification for one sidebar toggle button in the top area.
18
+ */
23
19
  interface IButtonSpec {
24
20
  /**
25
21
  * Stable widget id (required by `LabShell.add`).
@@ -29,15 +25,17 @@ interface IButtonSpec {
29
25
  * Command the button triggers and mirrors the state of.
30
26
  */
31
27
  command: string;
28
+ /**
29
+ * The icon rendered on the button.
30
+ */
32
31
  icon: LabIcon;
32
+ /**
33
+ * The localized tooltip of the button.
34
+ */
33
35
  caption: (trans: ReturnType<ITranslator['load']>) => string;
34
36
  /**
35
- * Rank within the `top` area. The main menu bar is added at rank 100, so a
36
- * negative rank lands the left button at the leading edge before it; a large
37
- * rank puts the right button after the menu, where `margin-left: auto`
38
- * (style/topBar.css) floats it to the far edge. xtralab's shipped config
39
- * disables the upstream Jupyter logo that otherwise occupies rank 0, so the
40
- * leading edge is free.
37
+ * Rank in the `top` area: the menu bar sits at 100 and the rank-0 upstream
38
+ * logo is disabled; `margin-left: auto` (topBar.css) floats the right button.
41
39
  */
42
40
  rank: number;
43
41
  /**
@@ -66,17 +64,10 @@ const BUTTONS: IButtonSpec[] = [
66
64
  ];
67
65
 
68
66
  /**
69
- * Add two icon buttons to the top bar that toggle the left and right side
70
- * areas, mirroring the macOS-style sidebar buttons: a left-sidebar button at
71
- * the leading edge and a right-sidebar button at the far edge.
72
- *
73
- * Each is a `CommandToolbarButton` wrapping an existing
74
- * `application:toggle-{left,right}-area` command, so clicking it runs the
75
- * same toggle as the View menu and the button reflects the command's state —
76
- * pressed while the matching sidebar is open, and disabled when the area is
77
- * empty. Note xtralab ships nothing in the right area by default (the
78
- * property inspector, table of contents and debugger are all disabled), so
79
- * the right button stays disabled until a widget is moved or added there.
67
+ * Add macOS-style sidebar toggle buttons to the top bar: left at the leading
68
+ * edge, right at the far edge. Each wraps the upstream toggle command and
69
+ * reflects its state — pressed while the sidebar is open, disabled while the
70
+ * area is empty (as the right area is by default).
80
71
  */
81
72
  const plugin: JupyterFrontEndPlugin<void> = {
82
73
  id: PLUGIN_ID,
@@ -92,40 +83,26 @@ const plugin: JupyterFrontEndPlugin<void> = {
92
83
  const { commands } = app;
93
84
  const trans = (translator ?? nullTranslator).load('jupyterlab');
94
85
 
95
- // The upstream toggle-{left,right}-area commands derive `isEnabled` from
96
- // `!labShell.isEmpty(side)` but don't fire `commandChanged` when widgets
97
- // move in or out of a side area. `CommandToolbarButton` only re-renders on
98
- // `commandChanged` for its own id, so the buttons need an explicit notify
99
- // whenever the shell layout shifts — `layoutModified` covers each side
100
- // handler's `_updated` (add/remove, expand/collapse), keeping both
101
- // `isEnabled` and `isToggled` in sync.
86
+ // The upstream toggle commands don't fire `commandChanged` on layout
87
+ // shifts, and `CommandToolbarButton` only re-renders on that signal.
102
88
  labShell.layoutModified.connect(() => {
103
89
  for (const spec of BUTTONS) {
104
90
  commands.notifyCommandChanged(spec.command);
105
91
  }
106
92
  });
107
93
 
108
- // Defer to `app.restored` so the upstream toggle commands are already in
109
- // the registry: `CommandToolbarButton` renders nothing until its command
110
- // exists and only re-renders on `commandChanged` of type `changed` /
111
- // `many-changed` (not `added`), so mounting earlier could leave a button
112
- // blank until the next unrelated command change.
94
+ // Defer to `app.restored`: `CommandToolbarButton` renders nothing until
95
+ // its command exists and doesn't re-render on the `added` change type.
113
96
  void app.restored.then(() => {
114
97
  for (const spec of BUTTONS) {
115
98
  const button = new CommandToolbarButton({
116
99
  commands,
117
100
  id: spec.command,
118
101
  icon: spec.icon,
119
- // Empty label keeps the button icon-only: the override is forwarded
120
- // verbatim and the component skips the label span when it is falsy.
121
102
  label: '',
122
103
  caption: spec.caption(trans),
123
- // Toggle on mousedown without focusing the button. Otherwise
124
- // ToolbarButtonComponent calls `event.target.focus()` on click,
125
- // leaving the stealth button showing a focus fill/outline (the
126
- // stray "border") until you click elsewhere — unwanted chrome for a
127
- // title-bar control. Keyboard Tab focus still works, so this stays
128
- // accessible.
104
+ // ToolbarButtonComponent otherwise focuses the button on click,
105
+ // leaving a stray focus fill on this title-bar control; Tab still works.
129
106
  noFocusOnClick: true
130
107
  });
131
108
  button.id = spec.id;
@@ -14,18 +14,12 @@ import { IWalkthroughMedia, IWalkthroughStep, WalkthroughPanel } from './panel';
14
14
 
15
15
  const PLUGIN_ID = 'xtralab:walkthrough';
16
16
 
17
- /**
18
- * Append a step to the read-only walkthrough panel.
19
- */
20
17
  const WALKTHROUGH_COMMAND = 'xtralab:walkthrough';
21
18
 
22
19
  const HIGHLIGHT_LINES_COMMAND = 'xtralab:highlight-lines';
23
20
 
24
21
  const PANEL_ID = 'xtralab-walkthrough';
25
22
 
26
- /**
27
- * Pull a `{ mimeType, data }` media object out of a JSON command argument.
28
- */
29
23
  function readMedia(value: unknown): IWalkthroughMedia | undefined {
30
24
  if (
31
25
  value &&
@@ -54,15 +48,10 @@ function toLine(value: unknown): number | undefined {
54
48
  }
55
49
 
56
50
  /**
57
- * Contribute `xtralab:walkthrough`: build a persistent, read-only walkthrough
58
- * in the right side area instead of narrating only in the agent's chat.
59
- *
60
- * Each call appends a step (Markdown prose, an optional embedded visual, and an
61
- * optional code reference). When a step names a file, the editor follows along
62
- * (opening it full-width in the main area, no split) and its lines are
63
- * highlighted; the step also keeps a button so the user can jump back to it
64
- * later. The panel accumulates the whole tour beside the code, so the user can
65
- * read at their own pace rather than chasing the chat.
51
+ * Contributes `xtralab:walkthrough`: each call appends a step (Markdown prose,
52
+ * optional visual, optional code reference) to a persistent read-only panel in
53
+ * the right side area, so the tour accumulates beside the code instead of
54
+ * scrolling away in the agent's chat.
66
55
  */
67
56
  const plugin: JupyterFrontEndPlugin<void> = {
68
57
  id: PLUGIN_ID,
@@ -89,9 +78,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
89
78
  panel.title.icon = tocIcon;
90
79
  panel.title.label = trans.__('Walkthrough');
91
80
  panel.title.caption = trans.__('Walkthrough');
92
- // Closable so it gets a close button if the user drags it out of the
93
- // side area into the main document area. Closing disposes it; the next
94
- // xtralab:walkthrough call recreates it back in the side area.
81
+ // Closable so a drag into the main area gets a close button; closing
82
+ // disposes, and the next call recreates the panel in the side area.
95
83
  panel.title.closable = true;
96
84
  labShell.add(panel, 'right', { rank: 1000, type: 'Walkthrough' });
97
85
  const created = panel;
@@ -188,11 +176,9 @@ const plugin: JupyterFrontEndPlugin<void> = {
188
176
  );
189
177
  }
190
178
 
191
- // Reveal the panel, then render the step into it.
192
179
  labShell.activateById(current.id);
193
180
  await current.addStep(step);
194
181
 
195
- // Let the editor follow the newest step.
196
182
  if (path && args['reveal'] !== false) {
197
183
  await commands.execute(HIGHLIGHT_LINES_COMMAND, {
198
184
  path,
@@ -15,7 +15,13 @@ const HIGHLIGHT_LINES_COMMAND = 'xtralab:highlight-lines';
15
15
  * A rich visual embedded in a step (rendered through the rendermime registry).
16
16
  */
17
17
  export interface IWalkthroughMedia {
18
+ /**
19
+ * The MIME type of the media payload.
20
+ */
18
21
  mimeType: string;
22
+ /**
23
+ * The payload handed to the renderer for the MIME type.
24
+ */
19
25
  data: ReadonlyPartialJSONValue;
20
26
  }
21
27
 
@@ -23,30 +29,56 @@ export interface IWalkthroughMedia {
23
29
  * One step of a walkthrough. Every field is optional, but a step needs at least one.
24
30
  */
25
31
  export interface IWalkthroughStep {
32
+ /**
33
+ * A heading rendered above the step content.
34
+ */
26
35
  title?: string;
36
+ /**
37
+ * The body of the step, rendered as Markdown.
38
+ */
27
39
  body?: string;
40
+ /**
41
+ * A rich visual rendered after the body.
42
+ */
28
43
  media?: IWalkthroughMedia;
44
+ /**
45
+ * The file the step points at; when set, the step renders a jump link.
46
+ */
29
47
  path?: string;
48
+ /**
49
+ * The first line to highlight when the jump link is followed.
50
+ */
30
51
  line?: number;
52
+ /**
53
+ * The last line of the highlighted range.
54
+ */
31
55
  endLine?: number;
32
56
  }
33
57
 
34
58
  export namespace WalkthroughPanel {
59
+ /**
60
+ * The instantiation options for a walkthrough panel.
61
+ */
35
62
  export interface IOptions {
63
+ /**
64
+ * The rendermime registry used to render step bodies and media.
65
+ */
36
66
  rendermime: IRenderMimeRegistry;
67
+ /**
68
+ * The command registry used to execute the jump-to-line command.
69
+ */
37
70
  commands: CommandRegistry;
71
+ /**
72
+ * The translation bundle for UI strings.
73
+ */
38
74
  trans: TranslationBundle;
39
75
  }
40
76
  }
41
77
 
42
78
  /**
43
79
  * A read-only, scrollable column of walkthrough steps for the side area.
44
- *
45
- * The agent appends steps as it narrates, so the explanation lives beside the
46
- * code the user is looking at and persists for them to read at their own pace,
47
- * rather than scrolling away in the chat. Each step renders Markdown (with code
48
- * snippets, Mermaid, math), can embed a rich visual, and can offer a button
49
- * that opens the referenced file and highlights its lines.
80
+ * The agent appends steps as it narrates, so the explanation persists beside
81
+ * the code instead of scrolling away in the chat.
50
82
  */
51
83
  export class WalkthroughPanel extends Panel {
52
84
  constructor(options: WalkthroughPanel.IOptions) {
@@ -67,9 +99,8 @@ export class WalkthroughPanel extends Panel {
67
99
  }
68
100
 
69
101
  /**
70
- * Dispose on close (e.g. the close button when the panel has been dragged to
71
- * the main area) rather than leaving a detached, reusable widget behind. The
72
- * next `xtralab:walkthrough` call recreates the panel in the side area.
102
+ * Dispose on close (e.g. after a drag to the main area) instead of leaving a
103
+ * detached widget; the next `xtralab:walkthrough` call recreates the panel.
73
104
  */
74
105
  protected onCloseRequest(msg: Message): void {
75
106
  super.onCloseRequest(msg);
@@ -103,7 +134,6 @@ export class WalkthroughPanel extends Panel {
103
134
  card.addWidget(this._jumpButton(step.path, step.line, step.endLine));
104
135
  }
105
136
 
106
- // Bring the newest step into view.
107
137
  this.node.scrollTop = this.node.scrollHeight;
108
138
  }
109
139
 
package/style/about.css CHANGED
@@ -1,10 +1,5 @@
1
- /*
2
- * About dialog (xtralab:about). The header block is the dialog title, so it
3
- * inherits the jp-Dialog-header type (size2/600 under chrome.css) — the
4
- * wordmark scales up from there and the version line drops back to body
5
- * size, weight and a muted color.
6
- */
7
-
1
+ /* The header block is the dialog title, so it inherits the jp-Dialog-header
2
+ * type (size2/600 under chrome.css). */
8
3
  .jp-xtralab-About-header {
9
4
  display: flex;
10
5
  align-items: center;