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,41 +12,6 @@ import { SessionRegistry } from './model';
12
12
  import { IAgentTerminals } from './tokens';
13
13
  import { RunningTerminals } from './widget';
14
14
  const PLUGIN_ID = 'xtralab:terminals';
15
- /**
16
- * Adds a left-sidebar panel that lists every running terminal session.
17
- *
18
- * Each row is labelled with the *real* title the running program
19
- * published — the launcher's agent name, or whatever title an xterm
20
- * escape sequence set — which the registry caches so it survives the
21
- * user closing the tab while the session keeps running on the server.
22
- * JupyterLab's built-in "Running Terminals and Kernels" panel lists the
23
- * same sessions but only by their `terminals/<n>` name, so this panel
24
- * resolves and caches the published title to show something meaningful.
25
- * Rows running a coding agent carry a smaller second line below the
26
- * title with the agent's latest line of output, so the panel shows what
27
- * each agent is doing at a glance — on by default, and switchable off
28
- * through the `showAgentActivity` setting.
29
- *
30
- * Clicking a row activates the existing tab if one is open, or reopens
31
- * the session in a fresh terminal widget (`terminal:open`). The inline
32
- * `×` button shuts the session down on the server. The Terminals
33
- * section's title toolbar carries a `+` button and a stop button (the
34
- * latter shuts every session down at once, after a confirmation).
35
- *
36
- * The list is one movable section, and other panels' sections can move in.
37
- *
38
- * The `+` button drops down a menu — built from the launcher's shared
39
- * `IAgentRegistry` — listing each available agent (Claude, Codex, …)
40
- * followed by a plain terminal, so starting an agent session is as
41
- * consistent here as in the launcher and reuses the very same registered
42
- * commands and icons. When the launcher is disabled or no agents are
43
- * installed, the button falls back to opening a plain terminal directly.
44
- *
45
- * The plugin also provides {@link IAgentTerminals} — the sessions with a
46
- * detection-confirmed running agent, plus a "paste a prompt into one"
47
- * action — which the ask-agent popup uses to offer running agents as
48
- * targets next to "new terminal".
49
- */
50
15
  const plugin = {
51
16
  id: PLUGIN_ID,
52
17
  description: 'A left-sidebar panel listing every running terminal session by its real (program-published) title, with activate/reopen, shutdown and new-terminal actions.',
@@ -64,13 +29,8 @@ const plugin = {
64
29
  ],
65
30
  activate: (app, tracker, restorer, translator, agentRegistry, editorRegistry, agentSessions, settingRegistry, movableSections) => {
66
31
  const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('jupyterlab');
67
- // Resolve a running agent/editor identifier to an icon: the matching
68
- // agent's logo, the matching editor's logo (Neovim/Vim), or the plain
69
- // terminal icon when nothing recognised is running. Detection reports
70
- // either the configured `command` or the canonical `id` (see
71
- // `detectCommands`), so a row whose command is an alias — e.g. `ccm` for
72
- // `claude` — still resolves to the right logo via its id. Reads the
73
- // registries live so it tracks settings changes. Used to badge each row.
32
+ // Detection reports either the configured `command` or the canonical `id`,
33
+ // so an aliased command (e.g. `ccm` for `claude`) still maps to its logo.
74
34
  const iconForCommand = (command) => {
75
35
  var _a;
76
36
  if (!command) {
@@ -80,18 +40,9 @@ const plugin = {
80
40
  if (agent) {
81
41
  return agent.icon;
82
42
  }
83
- // A terminal running an editor (Neovim/Vim, or a user-configured one) is
84
- // badged with its logo, the same as an agent.
85
43
  const editor = editorRegistry === null || editorRegistry === void 0 ? void 0 : editorRegistry.editors.find(e => e.command === command || e.id === command);
86
44
  return (_a = editor === null || editor === void 0 ? void 0 : editor.icon) !== null && _a !== void 0 ? _a : terminalIcon;
87
45
  };
88
- // The names the server should look for in each terminal's process tree:
89
- // for every agent and editor, its configured `command` plus its canonical
90
- // `id`. The id is the real CLI name (e.g. `claude`, `nvim`), so an agent
91
- // whose command points at an alias — e.g. `ccm` running `claude` — is
92
- // still recognised by the process it actually spawns. Read live so the
93
- // list tracks settings changes; deduplicated since command and id usually
94
- // coincide.
95
46
  const detectCommands = () => {
96
47
  var _a, _b;
97
48
  const names = new Set();
@@ -105,10 +56,6 @@ const plugin = {
105
56
  }
106
57
  return Array.from(names);
107
58
  };
108
- // Whether a detected command/id belongs to a coding agent rather than an
109
- // editor. Only agent sessions get a latest-activity line (editor
110
- // terminals stay badge-only), and only they are offered as prompt
111
- // targets through `IAgentTerminals`.
112
59
  const isAgentCommand = (command) => {
113
60
  var _a;
114
61
  return (_a = agentRegistry === null || agentRegistry === void 0 ? void 0 : agentRegistry.agents.some(a => a.command === command || a.id === command)) !== null && _a !== void 0 ? _a : false;
@@ -116,18 +63,13 @@ const plugin = {
116
63
  const registry = new SessionRegistry({
117
64
  serviceManager: app.serviceManager,
118
65
  tracker,
119
- // The shell tells the registry which widget is current, so the panel can
120
- // highlight the terminal that is the current main-area widget (and
121
- // nothing while a notebook or other widget is current instead).
122
66
  shell: app.shell,
123
67
  agentSessions,
124
68
  detectCommands,
125
69
  isAgentCommand
126
70
  });
127
- // Mirror the agent/editor detected in each open terminal onto its main-area
128
- // tab icon, so the tab matches its sidebar row. Re-running on every
129
- // `stateChanged` is safe: `Title.icon` ignores an unchanged assignment, so
130
- // the writes neither loop nor churn.
71
+ // `Title.icon` ignores an unchanged assignment, so re-running per
72
+ // stateChanged is cheap.
131
73
  const syncTabIcons = () => {
132
74
  tracker.forEach(widget => {
133
75
  const session = widget.content.session;
@@ -140,10 +82,8 @@ const plugin = {
140
82
  registry.stateChanged.connect(syncTabIcons);
141
83
  syncTabIcons();
142
84
  const onActivate = (name) => {
143
- // `terminal:open` is the upstream entry point that handles both
144
- // sides of this: if a widget is already attached to the named
145
- // session it activates that tab, otherwise it spins up a fresh
146
- // widget connected to the live session.
85
+ // `terminal:open` activates an attached tab or spins up a fresh widget
86
+ // connected to the live session.
147
87
  void app.commands.execute('terminal:open', { name });
148
88
  };
149
89
  const onShutdown = (name) => {
@@ -152,10 +92,6 @@ const plugin = {
152
92
  });
153
93
  };
154
94
  const onShutdownAll = () => {
155
- // Tearing down every session at once is hard to undo (each may be a
156
- // running agent), so confirm before calling the manager's bulk
157
- // shutdown. `runningChanged` then clears the list and the panel
158
- // re-renders empty.
159
95
  void showDialog({
160
96
  title: trans.__('Shut Down All Terminals?'),
161
97
  body: trans.__('Are you sure you want to permanently shut down all running terminals?'),
@@ -173,19 +109,8 @@ const plugin = {
173
109
  console.error(`xtralab: failed to shut down all terminals: ${reason}`);
174
110
  });
175
111
  };
176
- // The header "+" button. With the launcher's agent registry available
177
- // it drops down a menu of the available agents (reusing their registered
178
- // `xtralab:start-agent:<id>` commands, so the icons and labels match the
179
- // launcher exactly) followed by a separator and a plain terminal. Built
180
- // lazily and repopulated on each open so it always reflects the current,
181
- // settings-driven agent list. Without the registry (launcher disabled)
182
- // or with no agents installed, there is nothing to choose between, so
183
- // the button opens a plain terminal directly in one click.
184
- //
185
- // `MenuSvg` (not the bare Lumino `Menu`) is what every JupyterLab menu
186
- // uses: its renderer applies the `menuItem` LabIcon stylesheet, which
187
- // sizes the agent icons to 16px and centers them vertically — the bare
188
- // `Menu` renders the raw, oversized, misaligned SVGs.
112
+ // `MenuSvg`, not the bare Lumino `Menu`: its renderer applies the `menuItem`
113
+ // LabIcon stylesheet — the bare menu renders raw, oversized SVGs.
189
114
  let newMenu = null;
190
115
  const onCreate = (anchor) => {
191
116
  var _a;
@@ -214,15 +139,8 @@ const plugin = {
214
139
  onShutdownAll,
215
140
  onCreate
216
141
  });
217
- // Added to the left sidebar. The shipped `layout` setting in
218
- // jupyter-config/labconfig gives each sidebar widget a default rank —
219
- // this Terminals panel ranks first, so running agents sit one click
220
- // away at the top. That setting assigns rank only and pins no area, so
221
- // the "Move Widget" context menu can relocate the panel and the layout
222
- // restorer remembers where the user puts it. The `rank` here is the
223
- // in-code fallback used when the setting is absent. Sessions restored
224
- // from a previous lab run land via `runningChanged` once the terminal
225
- // manager is ready, which the panel's `UseSignal` picks up.
142
+ // The shipped labconfig `layout` setting ranks this panel first (rank only,
143
+ // no area pin, so "Move Widget" works); this rank is the fallback.
226
144
  app.shell.add(panel, 'left', { rank: 1 });
227
145
  if (restorer) {
228
146
  restorer.add(panel, panel.id);
@@ -235,9 +153,6 @@ const plugin = {
235
153
  movableSections.registerTarget(PLUGIN_ID, trans.__('Terminals'), panel);
236
154
  panel.announceSections();
237
155
  }
238
- // The latest-activity line under each agent row is on by default; honour
239
- // the `showAgentActivity` setting so it can be turned off. Read on load and
240
- // re-applied on every change.
241
156
  if (settingRegistry) {
242
157
  settingRegistry
243
158
  .load(PLUGIN_ID)
@@ -246,9 +161,8 @@ const plugin = {
246
161
  registry.setActivityEnabled(boolOption(settings.composite.showAgentActivity, true));
247
162
  };
248
163
  applyActivitySetting();
249
- // Bind the slot to the panel so disposing the panel (which clears
250
- // its signal data) drops the connection — the disposed registry is
251
- // then never reached on a later settings change.
164
+ // Bound to the panel so disposing it drops the connection — the
165
+ // disposed registry is never reached on a later settings change.
252
166
  settings.changed.connect(applyActivitySetting, panel);
253
167
  })
254
168
  .catch(reason => {
@@ -265,9 +179,6 @@ const plugin = {
265
179
  });
266
180
  }
267
181
  };
268
- /**
269
- * Read a boolean setting value, falling back when it is missing or invalid.
270
- */
271
182
  function boolOption(value, fallback) {
272
183
  return typeof value === 'boolean' ? value : fallback;
273
184
  }
@@ -5,191 +5,114 @@ import type { ITerminal, ITerminalTracker } from '@jupyterlab/terminal';
5
5
  import type { IDisposable } from '@lumino/disposable';
6
6
  import { ISignal } from '@lumino/signaling';
7
7
  import type { IAgentSessions } from '../agentSessions';
8
- /**
9
- * The widget shape every entry in `ITerminalTracker` takes — kept here
10
- * so the registry's call sites read cleanly.
11
- */
12
8
  export type TerminalWidget = MainAreaWidget<ITerminal.ITerminal>;
13
9
  /**
14
- * Source-of-truth model for the running-terminals panel. Each running
15
- * terminal session known to the server is one entry; the registry caches
16
- * the last `widget.title.label` we observed so the agent name (or any
17
- * xterm-published title) survives the user closing the tab while the
18
- * session continues running on the backend.
19
- *
20
- * For sessions running a coding agent it also surfaces a *latest activity*
21
- * line — the freshest meaningful line of the terminal's output, read from the
22
- * open tab's xterm buffer on a poll (see {@link activityFor}) — so each row
23
- * shows what its agent is doing, not just its name.
24
- *
25
- * It also resolves *which agent is running* in each session, so the panel can
26
- * badge rows with the agent's logo. Two inputs feed that, reconciled by
27
- * {@link agentCommandFor}:
28
- * - an optimistic launch tag ({@link IAgentSessions}) written when we start
29
- * an agent ourselves — instant, but blind to the agent later exiting; and
30
- * - authoritative server-side process detection, polled here, which works
31
- * for hand-started agents too and clears once an agent exits.
32
- *
33
- * Upstream session signals:
34
- * - `serviceManager.terminals.runningChanged` is the authoritative
35
- * list of live sessions; everything not in it has been shut down
36
- * server-side and we must drop it.
37
- * - `tracker.widgetAdded` plus the per-widget `title.changed` /
38
- * `disposed` signals keep our label cache in sync with whatever
39
- * xterm/the launcher has set on the open tabs.
40
- *
41
- * `stateChanged` is emitted for every kind of update; the panel hooks it
42
- * through a `UseSignal` so a single subscription re-renders the list on
43
- * any change.
10
+ * Source-of-truth model for the running-terminals panel: live sessions,
11
+ * labels cached across tab closes, agent badges (launch tags reconciled with
12
+ * polled detection, see {@link agentCommandFor}), and per-row latest-activity
13
+ * lines. `stateChanged` fires on every kind of update.
44
14
  */
45
15
  export declare class SessionRegistry implements IDisposable {
46
16
  constructor(options: SessionRegistry.IOptions);
47
17
  /**
48
- * Emitted whenever the live session list, a cached label, or the detected
49
- * running agent changes.
18
+ * Emitted on any change to the session list, labels, badges, or activity.
50
19
  */
51
20
  get stateChanged(): ISignal<this, void>;
21
+ /**
22
+ * Whether the registry has been disposed.
23
+ */
52
24
  get isDisposed(): boolean;
53
25
  /**
54
- * Names of all live sessions, ordered by their stable rank so the
55
- * rendered list keeps a consistent order (roughly creation order) as
56
- * new sessions are added and old ones shut down.
26
+ * Names of all live sessions in stable (roughly creation) order.
57
27
  */
58
28
  sessionNames(): string[];
59
29
  /**
60
- * True iff the named session is still on the server. Used by the panel
61
- * to skip a row during the brief window between the session's shutdown
62
- * and the next `runningChanged` arriving.
30
+ * True iff the named session is still on the server.
63
31
  */
64
32
  has(name: string): boolean;
65
33
  /**
66
- * Display name for the session. The cache wins because it only
67
- * holds "real" labels (the launcher's agent name or an xterm escape
68
- * sequence — see `_cacheLabel` for the filter); reading it first
69
- * prevents the transient `Terminal {name}` an XTerm widget shows
70
- * during reconnect from flickering into the panel. The live widget
71
- * title is used when no cache exists, and the `Terminal {name}`
72
- * fallback covers sessions we have never seen a widget for (e.g.
73
- * surviving a lab reload).
34
+ * Display name for the session. The cache wins — it holds only "real"
35
+ * labels (see `_cacheLabel`), so the transient `Terminal {name}` an xterm
36
+ * widget shows during reconnect never flickers into the panel; the final
37
+ * fallback covers sessions never seen with a widget (e.g. a lab reload).
74
38
  */
75
39
  labelFor(name: string): string;
76
40
  /**
77
- * An identifier for the agent running in the session — its configured
78
- * command, or its canonical id when detection matched the spawned process by
79
- * id rather than by an aliased command — or `null` if none. Callers resolve
80
- * it to a logo through the plugin's `iconForCommand`, which accepts either.
81
- *
82
- * Server-side detection is authoritative whenever it reports a running
83
- * agent. A launch tag fills two gaps: the startup grace window right after
84
- * we launch an agent (so its logo shows before its process is detectable),
85
- * and any time detection is unavailable (older server, transient error).
86
- * Once the grace window has passed and detection has reported the session
87
- * as idle, the tag is ignored — that is how the badge clears when an agent
88
- * exits.
41
+ * Agent identifier for the session (configured command or canonical id), or
42
+ * `null`. Detection wins when it reports an agent; a launch tag fills the
43
+ * grace window and detection outages, and is ignored once detection says
44
+ * idle — that is how the badge clears when an agent exits.
89
45
  */
90
46
  agentCommandFor(name: string): string | null;
91
47
  /**
92
- * The agent command server-side detection currently reports for the
93
- * session, or `null` when it has not confirmed one (the session is idle,
94
- * not yet covered by a poll, or detection is unavailable). Unlike
95
- * {@link agentCommandFor} this never falls back to the optimistic launch
96
- * tags: callers about to *write into* a session use it, and text must only
97
- * ever be sent to a confirmed running agent — pasted into a shell prompt it
98
- * would be executed.
48
+ * The agent command detection currently confirms for the session, or
49
+ * `null`. Never falls back to launch tags: callers about to *write into* a
50
+ * session use it, and text pasted into a shell prompt would be executed.
99
51
  */
100
52
  detectedCommandFor(name: string): string | null;
101
53
  /**
102
- * The most recent meaningful line of output from the session's terminal, or
103
- * `null` when there is nothing to surface — no coding agent is running in the
104
- * session, its tab is closed (so there is no live buffer to read), or the
105
- * buffer holds only the agent's input box and chrome. Refreshed on a poll by
106
- * {@link _refreshActivity}; shown as a smaller line under the row's title.
107
- * Always `null` while the activity line is disabled (see
108
- * {@link setActivityEnabled}).
54
+ * The most recent meaningful line of the session's output, or `null` when
55
+ * nothing qualifies (no running agent, closed tab, chrome-only buffer, or
56
+ * the activity line is disabled).
109
57
  */
110
58
  activityFor(name: string): string | null;
111
59
  /**
112
- * Turn the per-row latest-activity line on or off, driven by the
113
- * `xtralab:terminals` `showAgentActivity` setting. When turned off the
114
- * activity poll stops reading terminal buffers and any cached lines are
115
- * dropped, so rows fall back to their title alone; when turned back on the
116
- * lines are repopulated on the spot. A no-op when the value is unchanged.
60
+ * Turn the per-row activity line on or off (the `showAgentActivity`
61
+ * setting). Off drops cached lines; on repopulates them on the spot.
117
62
  */
118
63
  setActivityEnabled(enabled: boolean): void;
119
64
  /**
120
- * Return the open widget for a session, if any. The panel uses this to
121
- * switch behavior between "activate existing tab" and "open a new tab
122
- * connected to the live session".
65
+ * The open widget for a session, if any.
123
66
  */
124
67
  widgetFor(name: string): TerminalWidget | null;
125
68
  /**
126
- * Session name of the terminal that is currently the active widget in the
127
- * shell's main area, or `null` when that widget is not a terminal (for
128
- * example a notebook or text editor is current). The panel uses this to
129
- * highlight the current terminal's row — mirroring how the file browser
130
- * surfaces the open document — and to leave every row unhighlighted while a
131
- * non-terminal tab is current.
69
+ * Session name of the terminal that is the shell's current main-area
70
+ * widget, or `null` when the current widget is not a terminal.
132
71
  */
133
72
  currentSessionName(): string | null;
134
73
  /**
135
- * Stable per-session rank assigned in observation order. Used to keep
136
- * the rendered list in a steady order so rows don't reshuffle as
137
- * sessions come and go. Cleaned up when the session is shut down so the
138
- * counter does not grow without bound across long sessions.
74
+ * Stable per-session rank in observation order, so rows don't reshuffle as
75
+ * sessions come and go.
139
76
  */
140
77
  rankFor(name: string): number;
78
+ /**
79
+ * Dispose of the registry's polls and signal connections.
80
+ */
141
81
  dispose(): void;
142
82
  private _refreshLive;
143
83
  private _onRunningChanged;
144
84
  /**
145
- * Adopt `next` as the live set and prune every per-session map for
146
- * sessions that have gone away — labels, ranks, first-seen timestamps,
147
- * detection results, and the shared launch tag. Without this the maps (and
148
- * the rank counter) would grow without bound as terminals come and go.
85
+ * Adopt `next` as the live set and prune every per-session map, so the
86
+ * maps and rank counter don't grow without bound.
149
87
  */
150
88
  private _reconcileLive;
151
89
  /**
152
- * Poll body: ask the server which agent runs in each terminal and update
153
- * the detection map. On failure we keep the previous results rather than
154
- * clearing them, so a transient error doesn't strip every badge.
90
+ * Poll body: update the detection map from the server. On failure the
91
+ * previous results are kept, so a transient error doesn't strip every badge.
155
92
  */
156
93
  private _refreshDetection;
157
94
  /**
158
- * Poll body: re-read the buffer of each open coding-agent terminal and cache
159
- * its latest meaningful line of output. Only sessions that have a running
160
- * *agent* (not an editor) and an open tab qualify — a closed tab has no live
161
- * buffer, editors run full-screen UIs that are not "activity", and plain
162
- * shells would only echo their prompt. While a tab is reopening (its xterm
163
- * is not ready yet) any existing line is kept; once the buffer is readable
164
- * but has nothing worth showing the line is dropped, so a screen the agent
165
- * has cleared doesn't leave a frozen line behind. Cached lines for sessions
166
- * that no longer qualify are pruned. Emits only when something changed.
95
+ * Poll body: cache the latest meaningful output line of each open agent
96
+ * terminal (closed tabs have no live buffer; editors and shells don't
97
+ * qualify). Emits only when something changed.
167
98
  */
168
99
  private _refreshActivity;
169
100
  private _onTagChanged;
170
101
  private _onWidgetAdded;
171
102
  private _onShellCurrentChanged;
172
103
  /**
173
- * Recompute which terminal (if any) is the active main-area widget and emit
174
- * only when it changes. The terminal tracker tells us whether the shell's
175
- * current widget is one of our terminals; anything else — a notebook, an
176
- * editor, or nothing — clears the highlight.
104
+ * Recompute which terminal (if any) is the active main-area widget; emits
105
+ * only on change. Anything not a tracked terminal clears the highlight.
177
106
  */
178
107
  private _updateCurrent;
179
108
  private _trackWidget;
180
109
  private _untrackWidget;
181
110
  private _onTitleChanged;
182
111
  /**
183
- * Update the cached label for a session, but only when the new
184
- * label is "real" — non-empty and not one of the transient defaults
185
- * the XTerm widget cycles through during reconnect (`'...'` while
186
- * the websocket is opening, `'Terminal {name}'` once
187
- * `_initialConnection` fires). Without the filter, briefly
188
- * reopening a tab while an agent has yet to re-emit its xterm
189
- * title escape sequence would clobber the cached agent name with
190
- * `Terminal 1`. Live widget titles still display whatever the widget
191
- * currently holds because `labelFor` consults the widget first;
192
- * the filter only affects what survives a tab close.
112
+ * Cache a label only when it is "real" — not `'...'` or `Terminal {name}`,
113
+ * the transient defaults xterm cycles through during reconnect. Without the
114
+ * filter, reopening a tab before the agent re-emits its title escape would
115
+ * clobber the cached agent name.
193
116
  */
194
117
  private _cacheLabel;
195
118
  private _onWidgetDisposed;
@@ -217,15 +140,21 @@ export declare class SessionRegistry implements IDisposable {
217
140
  * Construction options for {@link SessionRegistry}.
218
141
  */
219
142
  export declare namespace SessionRegistry {
143
+ /**
144
+ * The instantiation options for a session registry.
145
+ */
220
146
  interface IOptions {
147
+ /**
148
+ * The service manager whose terminal manager supplies the sessions.
149
+ */
221
150
  serviceManager: ServiceManager.IManager;
151
+ /**
152
+ * The tracker of open terminal widgets.
153
+ */
222
154
  tracker: ITerminalTracker;
223
155
  /**
224
- * The application shell, used to tell which widget is currently active so
225
- * the panel can highlight the terminal that is the current main-area
226
- * widget — and highlight nothing when that widget is not a terminal (a
227
- * notebook, an editor, …). Optional: without it, or on a shell that cannot
228
- * report `currentChanged`, the highlight stays off.
156
+ * Used to highlight the row of the current main-area terminal. Optional:
157
+ * without it (or its `currentChanged`) the highlight stays off.
229
158
  */
230
159
  shell?: JupyterFrontEnd.IShell | null;
231
160
  /**
@@ -234,19 +163,15 @@ export declare namespace SessionRegistry {
234
163
  */
235
164
  agentSessions?: IAgentSessions | null;
236
165
  /**
237
- * Returns the names the server should look for when detecting running
238
- * agents — each agent's command together with its canonical id, so a
239
- * command pointed at an alias (e.g. `ccm` running `claude`) is still
240
- * matched by the process it spawns. Read on every poll so it tracks the
241
- * live agent list.
166
+ * Names to detect: each agent's command plus its canonical id, so an
167
+ * aliased command (e.g. `ccm` running `claude`) is still matched by the
168
+ * process it spawns. Read on every poll.
242
169
  */
243
170
  detectCommands?: () => string[];
244
171
  /**
245
- * Whether a detected command (or id) belongs to a coding agent rather than
246
- * an editor. Only agent sessions get a latest-activity line — editors
247
- * (Neovim/Vim) are badged too, but run full-screen UIs whose buffer is not
248
- * meaningfully "activity". Defaults to treating every detected command as an
249
- * agent.
172
+ * Whether a detected command (or id) belongs to a coding agent rather
173
+ * than an editor; only agent sessions get a latest-activity line.
174
+ * Defaults to treating every detected command as an agent.
250
175
  */
251
176
  isAgentCommand?: (command: string) => boolean;
252
177
  }