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
@@ -1,66 +1,19 @@
1
1
  import { Poll } from '@lumino/polling';
2
2
  import { Signal } from '@lumino/signaling';
3
3
  import { fetchRunningAgents } from './detection';
4
- /**
5
- * How often to ask the server which agent (if any) is running in each
6
- * terminal. Snappy enough that a manually-started agent's logo shows up
7
- * within a few seconds, light enough that walking the shells' process trees
8
- * stays negligible.
9
- */
10
4
  const DETECT_POLL_INTERVAL_MS = 3000;
11
- /**
12
- * Upper bound on the exponential backoff when detection fails repeatedly
13
- * (e.g. the endpoint is missing on an older server). Matches the rest of the
14
- * plugin's polls.
15
- */
16
5
  const DETECT_POLL_MAX_MS = 300000;
17
6
  /**
18
- * Grace window after a session first appears during which an optimistic
19
- * launch tag outranks a `null` detection result. It covers the gap between
20
- * issuing an agent's command and its process actually being spawnable, so the
21
- * freshly-launched logo doesn't blink off if a detection poll lands in that
22
- * sliver. Comfortably longer than a cold agent start; short enough that a tag
23
- * for an agent that never really started clears quickly.
7
+ * Window during which a fresh launch tag outranks a `null` detection result:
8
+ * covers the gap between launching an agent and its process becoming visible.
24
9
  */
25
10
  const LAUNCH_GRACE_MS = 4000;
26
- /**
27
- * How often to re-read each open coding-agent terminal's output buffer to
28
- * refresh the "latest activity" line shown under its row. Brisk enough to feel
29
- * live while an agent works, cheap because it only walks the last screenful of
30
- * a handful of terminals and emits only when a line actually changes.
31
- */
32
11
  const ACTIVITY_POLL_INTERVAL_MS = 1500;
33
12
  /**
34
- * Source-of-truth model for the running-terminals panel. Each running
35
- * terminal session known to the server is one entry; the registry caches
36
- * the last `widget.title.label` we observed so the agent name (or any
37
- * xterm-published title) survives the user closing the tab while the
38
- * session continues running on the backend.
39
- *
40
- * For sessions running a coding agent it also surfaces a *latest activity*
41
- * line — the freshest meaningful line of the terminal's output, read from the
42
- * open tab's xterm buffer on a poll (see {@link activityFor}) — so each row
43
- * shows what its agent is doing, not just its name.
44
- *
45
- * It also resolves *which agent is running* in each session, so the panel can
46
- * badge rows with the agent's logo. Two inputs feed that, reconciled by
47
- * {@link agentCommandFor}:
48
- * - an optimistic launch tag ({@link IAgentSessions}) written when we start
49
- * an agent ourselves — instant, but blind to the agent later exiting; and
50
- * - authoritative server-side process detection, polled here, which works
51
- * for hand-started agents too and clears once an agent exits.
52
- *
53
- * Upstream session signals:
54
- * - `serviceManager.terminals.runningChanged` is the authoritative
55
- * list of live sessions; everything not in it has been shut down
56
- * server-side and we must drop it.
57
- * - `tracker.widgetAdded` plus the per-widget `title.changed` /
58
- * `disposed` signals keep our label cache in sync with whatever
59
- * xterm/the launcher has set on the open tabs.
60
- *
61
- * `stateChanged` is emitted for every kind of update; the panel hooks it
62
- * through a `UseSignal` so a single subscription re-renders the list on
63
- * any change.
13
+ * Source-of-truth model for the running-terminals panel: live sessions,
14
+ * labels cached across tab closes, agent badges (launch tags reconciled with
15
+ * polled detection, see {@link agentCommandFor}), and per-row latest-activity
16
+ * lines. `stateChanged` fires on every kind of update.
64
17
  */
65
18
  export class SessionRegistry {
66
19
  constructor(options) {
@@ -86,17 +39,8 @@ export class SessionRegistry {
86
39
  this._tracker.widgetAdded.connect(this._onWidgetAdded, this);
87
40
  this._tracker.forEach(widget => this._trackWidget(widget));
88
41
  this._refreshLive();
89
- // Track which terminal is the current widget in the main area so the panel
90
- // can highlight its row — and highlight nothing while a notebook or any
91
- // other non-terminal tab is current instead. `currentChanged` is optional
92
- // on the shell interface (not every shell can switch focus), so guard it;
93
- // when it is absent the highlight stays off.
94
42
  (_f = (_e = this._shell) === null || _e === void 0 ? void 0 : _e.currentChanged) === null || _f === void 0 ? void 0 : _f.connect(this._onShellCurrentChanged, this);
95
43
  this._updateCurrent();
96
- // A freshly written launch tag should re-render the panel immediately
97
- // (show the logo) and again once the grace window closes (so a tag for
98
- // an agent that never started, or that detection later contradicts,
99
- // doesn't linger).
100
44
  (_g = this._agentSessions) === null || _g === void 0 ? void 0 : _g.changed.connect(this._onTagChanged, this);
101
45
  this._poll = new Poll({
102
46
  name: '@xtralab/terminals:runningAgents',
@@ -108,10 +52,8 @@ export class SessionRegistry {
108
52
  },
109
53
  standby: 'when-hidden'
110
54
  });
111
- // A second, faster poll reads the live output buffer of each open
112
- // coding-agent terminal to keep its "latest activity" line current. Kept
113
- // separate from the detection poll so reading xterm buffers neither delays
114
- // nor is delayed by the server round-trip that drives the agent badges.
55
+ // Separate from the detection poll so reading xterm buffers neither
56
+ // delays nor is delayed by the server round-trip.
115
57
  this._activityPoll = new Poll({
116
58
  name: '@xtralab/terminals:activity',
117
59
  factory: () => this._refreshActivity(),
@@ -120,19 +62,19 @@ export class SessionRegistry {
120
62
  });
121
63
  }
122
64
  /**
123
- * Emitted whenever the live session list, a cached label, or the detected
124
- * running agent changes.
65
+ * Emitted on any change to the session list, labels, badges, or activity.
125
66
  */
126
67
  get stateChanged() {
127
68
  return this._stateChanged;
128
69
  }
70
+ /**
71
+ * Whether the registry has been disposed.
72
+ */
129
73
  get isDisposed() {
130
74
  return this._isDisposed;
131
75
  }
132
76
  /**
133
- * Names of all live sessions, ordered by their stable rank so the
134
- * rendered list keeps a consistent order (roughly creation order) as
135
- * new sessions are added and old ones shut down.
77
+ * Names of all live sessions in stable (roughly creation) order.
136
78
  */
137
79
  sessionNames() {
138
80
  const names = Array.from(this._live);
@@ -140,22 +82,16 @@ export class SessionRegistry {
140
82
  return names;
141
83
  }
142
84
  /**
143
- * True iff the named session is still on the server. Used by the panel
144
- * to skip a row during the brief window between the session's shutdown
145
- * and the next `runningChanged` arriving.
85
+ * True iff the named session is still on the server.
146
86
  */
147
87
  has(name) {
148
88
  return this._live.has(name);
149
89
  }
150
90
  /**
151
- * Display name for the session. The cache wins because it only
152
- * holds "real" labels (the launcher's agent name or an xterm escape
153
- * sequence — see `_cacheLabel` for the filter); reading it first
154
- * prevents the transient `Terminal {name}` an XTerm widget shows
155
- * during reconnect from flickering into the panel. The live widget
156
- * title is used when no cache exists, and the `Terminal {name}`
157
- * fallback covers sessions we have never seen a widget for (e.g.
158
- * surviving a lab reload).
91
+ * Display name for the session. The cache wins — it holds only "real"
92
+ * labels (see `_cacheLabel`), so the transient `Terminal {name}` an xterm
93
+ * widget shows during reconnect never flickers into the panel; the final
94
+ * fallback covers sessions never seen with a widget (e.g. a lab reload).
159
95
  */
160
96
  labelFor(name) {
161
97
  const cached = this._labels.get(name);
@@ -169,18 +105,10 @@ export class SessionRegistry {
169
105
  return `Terminal ${name}`;
170
106
  }
171
107
  /**
172
- * An identifier for the agent running in the session — its configured
173
- * command, or its canonical id when detection matched the spawned process by
174
- * id rather than by an aliased command — or `null` if none. Callers resolve
175
- * it to a logo through the plugin's `iconForCommand`, which accepts either.
176
- *
177
- * Server-side detection is authoritative whenever it reports a running
178
- * agent. A launch tag fills two gaps: the startup grace window right after
179
- * we launch an agent (so its logo shows before its process is detectable),
180
- * and any time detection is unavailable (older server, transient error).
181
- * Once the grace window has passed and detection has reported the session
182
- * as idle, the tag is ignored — that is how the badge clears when an agent
183
- * exits.
108
+ * Agent identifier for the session (configured command or canonical id), or
109
+ * `null`. Detection wins when it reports an agent; a launch tag fills the
110
+ * grace window and detection outages, and is ignored once detection says
111
+ * idle — that is how the badge clears when an agent exits.
184
112
  */
185
113
  agentCommandFor(name) {
186
114
  var _a, _b, _c;
@@ -203,26 +131,18 @@ export class SessionRegistry {
203
131
  return null;
204
132
  }
205
133
  /**
206
- * The agent command server-side detection currently reports for the
207
- * session, or `null` when it has not confirmed one (the session is idle,
208
- * not yet covered by a poll, or detection is unavailable). Unlike
209
- * {@link agentCommandFor} this never falls back to the optimistic launch
210
- * tags: callers about to *write into* a session use it, and text must only
211
- * ever be sent to a confirmed running agent — pasted into a shell prompt it
212
- * would be executed.
134
+ * The agent command detection currently confirms for the session, or
135
+ * `null`. Never falls back to launch tags: callers about to *write into* a
136
+ * session use it, and text pasted into a shell prompt would be executed.
213
137
  */
214
138
  detectedCommandFor(name) {
215
139
  const detected = this._detected.get(name);
216
140
  return typeof detected === 'string' ? detected : null;
217
141
  }
218
142
  /**
219
- * The most recent meaningful line of output from the session's terminal, or
220
- * `null` when there is nothing to surface — no coding agent is running in the
221
- * session, its tab is closed (so there is no live buffer to read), or the
222
- * buffer holds only the agent's input box and chrome. Refreshed on a poll by
223
- * {@link _refreshActivity}; shown as a smaller line under the row's title.
224
- * Always `null` while the activity line is disabled (see
225
- * {@link setActivityEnabled}).
143
+ * The most recent meaningful line of the session's output, or `null` when
144
+ * nothing qualifies (no running agent, closed tab, chrome-only buffer, or
145
+ * the activity line is disabled).
226
146
  */
227
147
  activityFor(name) {
228
148
  var _a;
@@ -232,11 +152,8 @@ export class SessionRegistry {
232
152
  return (_a = this._activity.get(name)) !== null && _a !== void 0 ? _a : null;
233
153
  }
234
154
  /**
235
- * Turn the per-row latest-activity line on or off, driven by the
236
- * `xtralab:terminals` `showAgentActivity` setting. When turned off the
237
- * activity poll stops reading terminal buffers and any cached lines are
238
- * dropped, so rows fall back to their title alone; when turned back on the
239
- * lines are repopulated on the spot. A no-op when the value is unchanged.
155
+ * Turn the per-row activity line on or off (the `showAgentActivity`
156
+ * setting). Off drops cached lines; on repopulates them on the spot.
240
157
  */
241
158
  setActivityEnabled(enabled) {
242
159
  if (enabled === this._activityEnabled) {
@@ -244,8 +161,6 @@ export class SessionRegistry {
244
161
  }
245
162
  this._activityEnabled = enabled;
246
163
  if (enabled) {
247
- // Repopulate immediately rather than waiting for the next poll tick;
248
- // `_refreshActivity` emits `stateChanged` if it finds anything to show.
249
164
  void this._refreshActivity();
250
165
  }
251
166
  else {
@@ -254,30 +169,22 @@ export class SessionRegistry {
254
169
  }
255
170
  }
256
171
  /**
257
- * Return the open widget for a session, if any. The panel uses this to
258
- * switch behavior between "activate existing tab" and "open a new tab
259
- * connected to the live session".
172
+ * The open widget for a session, if any.
260
173
  */
261
174
  widgetFor(name) {
262
175
  var _a;
263
176
  return ((_a = this._tracker.find(widget => widget.content.session.name === name)) !== null && _a !== void 0 ? _a : null);
264
177
  }
265
178
  /**
266
- * Session name of the terminal that is currently the active widget in the
267
- * shell's main area, or `null` when that widget is not a terminal (for
268
- * example a notebook or text editor is current). The panel uses this to
269
- * highlight the current terminal's row — mirroring how the file browser
270
- * surfaces the open document — and to leave every row unhighlighted while a
271
- * non-terminal tab is current.
179
+ * Session name of the terminal that is the shell's current main-area
180
+ * widget, or `null` when the current widget is not a terminal.
272
181
  */
273
182
  currentSessionName() {
274
183
  return this._currentName;
275
184
  }
276
185
  /**
277
- * Stable per-session rank assigned in observation order. Used to keep
278
- * the rendered list in a steady order so rows don't reshuffle as
279
- * sessions come and go. Cleaned up when the session is shut down so the
280
- * counter does not grow without bound across long sessions.
186
+ * Stable per-session rank in observation order, so rows don't reshuffle as
187
+ * sessions come and go.
281
188
  */
282
189
  rankFor(name) {
283
190
  let rank = this._ranks.get(name);
@@ -287,6 +194,9 @@ export class SessionRegistry {
287
194
  }
288
195
  return rank;
289
196
  }
197
+ /**
198
+ * Dispose of the registry's polls and signal connections.
199
+ */
290
200
  dispose() {
291
201
  var _a, _b, _c;
292
202
  if (this._isDisposed) {
@@ -314,17 +224,13 @@ export class SessionRegistry {
314
224
  this._stateChanged.emit();
315
225
  }
316
226
  /**
317
- * Adopt `next` as the live set and prune every per-session map for
318
- * sessions that have gone away — labels, ranks, first-seen timestamps,
319
- * detection results, and the shared launch tag. Without this the maps (and
320
- * the rank counter) would grow without bound as terminals come and go.
227
+ * Adopt `next` as the live set and prune every per-session map, so the
228
+ * maps and rank counter don't grow without bound.
321
229
  */
322
230
  _reconcileLive(next) {
323
231
  var _a;
324
- // Names we had already seen, captured before we prune below — the set of
325
- // candidates whose launch tag may now need forgetting. (The tag map is
326
- // not enumerable, so we drive the prune from the sessions we know about;
327
- // `_firstSeen` has an entry for every session that has ever been live.)
232
+ // The tag map is not enumerable, so the tag prune below is driven from
233
+ // `_firstSeen`, which has an entry for every session ever live.
328
234
  const known = Array.from(this._firstSeen.keys());
329
235
  for (const name of next) {
330
236
  if (!this._firstSeen.has(name)) {
@@ -357,10 +263,8 @@ export class SessionRegistry {
357
263
  this._activity.delete(name);
358
264
  }
359
265
  }
360
- // Forget launch tags for sessions that have gone away. This matters for
361
- // correctness as well as bookkeeping: terminado reuses session names, so
362
- // a stale tag could otherwise mislabel a brand-new terminal that happens
363
- // to reuse a closed session's name.
266
+ // terminado reuses session names, so a stale tag could mislabel a
267
+ // brand-new terminal that reuses a closed session's name.
364
268
  for (const name of known) {
365
269
  if (!next.has(name)) {
366
270
  (_a = this._agentSessions) === null || _a === void 0 ? void 0 : _a.delete(name);
@@ -368,9 +272,8 @@ export class SessionRegistry {
368
272
  }
369
273
  }
370
274
  /**
371
- * Poll body: ask the server which agent runs in each terminal and update
372
- * the detection map. On failure we keep the previous results rather than
373
- * clearing them, so a transient error doesn't strip every badge.
275
+ * Poll body: update the detection map from the server. On failure the
276
+ * previous results are kept, so a transient error doesn't strip every badge.
374
277
  */
375
278
  async _refreshDetection() {
376
279
  const commands = this._detectCommands();
@@ -397,15 +300,9 @@ export class SessionRegistry {
397
300
  }
398
301
  }
399
302
  /**
400
- * Poll body: re-read the buffer of each open coding-agent terminal and cache
401
- * its latest meaningful line of output. Only sessions that have a running
402
- * *agent* (not an editor) and an open tab qualify — a closed tab has no live
403
- * buffer, editors run full-screen UIs that are not "activity", and plain
404
- * shells would only echo their prompt. While a tab is reopening (its xterm
405
- * is not ready yet) any existing line is kept; once the buffer is readable
406
- * but has nothing worth showing the line is dropped, so a screen the agent
407
- * has cleared doesn't leave a frozen line behind. Cached lines for sessions
408
- * that no longer qualify are pruned. Emits only when something changed.
303
+ * Poll body: cache the latest meaningful output line of each open agent
304
+ * terminal (closed tabs have no live buffer; editors and shells don't
305
+ * qualify). Emits only when something changed.
409
306
  */
410
307
  async _refreshActivity() {
411
308
  if (!this._activityEnabled) {
@@ -425,8 +322,8 @@ export class SessionRegistry {
425
322
  qualifying.add(name);
426
323
  const term = widget.content._term;
427
324
  if (!term) {
428
- // The tab is reopening and its xterm is not ready; keep any existing
429
- // line until the buffer can be read again.
325
+ // The tab is reopening; keep any existing line until its xterm buffer
326
+ // is readable again.
430
327
  continue;
431
328
  }
432
329
  const line = Private.readActivity(term);
@@ -437,8 +334,8 @@ export class SessionRegistry {
437
334
  }
438
335
  }
439
336
  else if (this._activity.delete(name)) {
440
- // Readable buffer with nothing to surface (e.g. the agent cleared its
441
- // screen) — drop the now-stale line instead of freezing it.
337
+ // Readable buffer with nothing to surface (e.g. a cleared screen) —
338
+ // drop the stale line instead of freezing it.
442
339
  changed = true;
443
340
  }
444
341
  }
@@ -454,8 +351,8 @@ export class SessionRegistry {
454
351
  }
455
352
  _onTagChanged() {
456
353
  this._stateChanged.emit();
457
- // Re-render once the grace window closes so a tag that detection never
458
- // confirmed (or has since contradicted) stops being shown.
354
+ // Re-emit once the grace window closes so a tag detection never confirmed
355
+ // (or has since contradicted) stops being shown.
459
356
  setTimeout(() => {
460
357
  if (!this._isDisposed) {
461
358
  this._stateChanged.emit();
@@ -470,10 +367,8 @@ export class SessionRegistry {
470
367
  this._updateCurrent();
471
368
  }
472
369
  /**
473
- * Recompute which terminal (if any) is the active main-area widget and emit
474
- * only when it changes. The terminal tracker tells us whether the shell's
475
- * current widget is one of our terminals; anything else — a notebook, an
476
- * editor, or nothing — clears the highlight.
370
+ * Recompute which terminal (if any) is the active main-area widget; emits
371
+ * only on change. Anything not a tracked terminal clears the highlight.
477
372
  */
478
373
  _updateCurrent() {
479
374
  var _a, _b;
@@ -506,16 +401,10 @@ export class SessionRegistry {
506
401
  this._stateChanged.emit();
507
402
  }
508
403
  /**
509
- * Update the cached label for a session, but only when the new
510
- * label is "real" — non-empty and not one of the transient defaults
511
- * the XTerm widget cycles through during reconnect (`'...'` while
512
- * the websocket is opening, `'Terminal {name}'` once
513
- * `_initialConnection` fires). Without the filter, briefly
514
- * reopening a tab while an agent has yet to re-emit its xterm
515
- * title escape sequence would clobber the cached agent name with
516
- * `Terminal 1`. Live widget titles still display whatever the widget
517
- * currently holds because `labelFor` consults the widget first;
518
- * the filter only affects what survives a tab close.
404
+ * Cache a label only when it is "real" — not `'...'` or `Terminal {name}`,
405
+ * the transient defaults xterm cycles through during reconnect. Without the
406
+ * filter, reopening a tab before the agent re-emits its title escape would
407
+ * clobber the cached agent name.
519
408
  */
520
409
  _cacheLabel(name, label) {
521
410
  if (!label) {
@@ -527,11 +416,8 @@ export class SessionRegistry {
527
416
  this._labels.set(name, label);
528
417
  }
529
418
  _onWidgetDisposed(widget) {
530
- // The widget is gone but the session may still be running on the
531
- // server — keep the cached label so the panel keeps the agent's name
532
- // when the user reopens the tab. We only clean up our subscriptions
533
- // here; the cache is purged by `runningChanged` once the session
534
- // itself goes away.
419
+ // The session may still be running on the server; the cached label stays
420
+ // until `runningChanged` purges it with the session itself.
535
421
  this._untrackWidget(widget);
536
422
  this._stateChanged.emit();
537
423
  }
@@ -539,8 +425,7 @@ export class SessionRegistry {
539
425
  var Private;
540
426
  (function (Private) {
541
427
  /**
542
- * Value-equality for two detection maps, so a poll that changes nothing
543
- * doesn't trigger a re-render.
428
+ * Whether two detection maps hold identical entries.
544
429
  */
545
430
  function detectedEqual(a, b) {
546
431
  if (a.size !== b.size) {
@@ -554,33 +439,21 @@ var Private;
554
439
  return true;
555
440
  }
556
441
  Private.detectedEqual = detectedEqual;
557
- /**
558
- * Rows above the cursor to scan when looking for the latest output.
559
- */
560
442
  const ACTIVITY_SCAN_ROWS = 64;
561
- /**
562
- * Clamp for the activity string so one runaway block can't bloat a row.
563
- */
564
443
  const ACTIVITY_MAX_LENGTH = 160;
565
444
  /**
566
- * Horizontal box-drawing / rule characters, treated as blanks when
567
- * sanitizing. Agents pad a status line or draw a separator with these (e.g.
568
- * `Worked for 1m 06s ────`), which is chrome, not text. Vertical bars are
569
- * deliberately excluded — {@link isMeaningfulActivity} relies on them to
570
- * recognise (and skip) the contents of an input/quote box.
445
+ * Horizontal rule characters treated as blanks when sanitizing (status-line
446
+ * padding is chrome, not text). Vertical bars are excluded on purpose —
447
+ * {@link isMeaningfulActivity} uses them to skip input/quote boxes.
571
448
  */
572
449
  const RULE_CHARS = new Set([
573
450
  0x2500, 0x2501, 0x2504, 0x2505, 0x2508, 0x2509, 0x254c, 0x254d, 0x2550
574
451
  ]);
575
452
  /**
576
- * The most recent meaningful line of agent output, or `null` if none is
577
- * found. Agents park the cursor in an input box at the bottom of the screen,
578
- * so the scan starts there and walks *up*, skipping that box, any hint or
579
- * footer beneath it, blank lines and separators, until it reaches the block
580
- * of real output nearest the input. It then rewinds to that block's first row
581
- * and stitches the block back together (see {@link joinBlock}), so a reply
582
- * the agent hard-wrapped across several rows reads as its opening sentence
583
- * rather than the trailing fragment left next to the cursor.
453
+ * The most recent meaningful line of agent output, or `null`. Agents park
454
+ * the cursor in a bottom input box, so the scan walks *up* past chrome to
455
+ * the nearest output block, then rewinds to that block's first row so a
456
+ * hard-wrapped reply reads as its opening sentence, not a trailing fragment.
584
457
  */
585
458
  function readActivity(term) {
586
459
  var _a;
@@ -594,8 +467,6 @@ var Private;
594
467
  if (!isMeaningfulActivity(lineText(buffer, row))) {
595
468
  continue;
596
469
  }
597
- // `row` is the bottom of the output block nearest the input; walk up
598
- // while rows stay meaningful to find the block's first row.
599
470
  let topRow = row;
600
471
  while (topRow > limit &&
601
472
  isMeaningfulActivity(lineText(buffer, topRow - 1))) {
@@ -607,7 +478,7 @@ var Private;
607
478
  }
608
479
  Private.readActivity = readActivity;
609
480
  /**
610
- * Sanitized text of one buffer row.
481
+ * Read a buffer row as sanitized text; empty when the row is missing.
611
482
  */
612
483
  function lineText(buffer, row) {
613
484
  var _a, _b;
@@ -615,10 +486,9 @@ var Private;
615
486
  }
616
487
  Private.lineText = lineText;
617
488
  /**
618
- * Stitch rows `[topRow, lastRow]` of one output block into a single string,
619
- * stopping once it is long enough to fill the row. A soft-wrapped row
620
- * continues the previous one mid-word, so it is appended directly; a hard
621
- * newline is a word boundary, so it is joined with a space.
489
+ * Stitch rows `[topRow, lastRow]` of one output block into a single string.
490
+ * A soft-wrapped row continues mid-word (appended directly); a hard newline
491
+ * is a word boundary (joined with a space).
622
492
  */
623
493
  function joinBlock(buffer, topRow, lastRow) {
624
494
  var _a;
@@ -648,9 +518,7 @@ var Private;
648
518
  }
649
519
  Private.clampActivity = clampActivity;
650
520
  /**
651
- * Collapse a raw buffer row into displayable text: replace control characters
652
- * and horizontal rule characters with spaces (so no escape sequence or drawn
653
- * separator rides along), squeeze runs of whitespace, and trim.
521
+ * Replace control and rule characters with spaces and collapse whitespace.
654
522
  */
655
523
  function sanitizeActivity(value) {
656
524
  var _a;
@@ -664,18 +532,10 @@ var Private;
664
532
  }
665
533
  Private.sanitizeActivity = sanitizeActivity;
666
534
  /**
667
- * Whether a sanitized row is worth showing as activity, i.e. real output
668
- * rather than chrome. Doubles as the block-boundary test for
669
- * {@link readActivity}'s walk up. A row is skipped when it:
670
- * - is blank or pure box-drawing (carries no letter or digit);
671
- * - begins with a vertical box-drawing bar (the contents of an input or
672
- * quote box), a prompt chevron (the input row and its ghost suggestion),
673
- * or Claude's tool-result / tip marker `⎿`; or
674
- * - is a transient status footer — one carrying a `for <time>` / `(<time>`
675
- * elapsed-time stamp, as agents print while and after they work
676
- * ("✻ Churned for 17s", "Working… (8s · …)", "— Worked for 1m 06s"). This
677
- * carries no real content, so skipping it lets the scan reach the reply
678
- * the agent wrote just above it.
535
+ * Whether a sanitized row is real output rather than chrome; doubles as
536
+ * {@link readActivity}'s block-boundary test. Skips rows without a letter
537
+ * or digit, rows starting with a box bar / prompt chevron / `⎿`, and
538
+ * elapsed-time status footers ("✻ Churned for 17s", "Working… (8s · …)").
679
539
  */
680
540
  function isMeaningfulActivity(text) {
681
541
  if (!text) {
@@ -10,15 +10,12 @@ export interface IAgentTerminalSession {
10
10
  */
11
11
  name: string;
12
12
  /**
13
- * The agent identifier server-side detection reported for the session:
14
- * the configured `command`, or the canonical agent `id` when the command
15
- * is an alias (e.g. `ccm` spawning `claude`). Matches an `IAgent` by
16
- * either field.
13
+ * The agent identifier detection reported: the configured `command`, or the
14
+ * canonical `id` when the command is an alias (e.g. `ccm` spawning `claude`).
17
15
  */
18
16
  command: string;
19
17
  /**
20
- * Display label — the session's real title (the launcher's agent name, or
21
- * whatever the running program published via an xterm escape sequence).
18
+ * Display label — the session's real (program-published) title.
22
19
  */
23
20
  label: string;
24
21
  /**
@@ -30,12 +27,9 @@ export interface IAgentTerminalSession {
30
27
  /**
31
28
  * Running agent terminals, and a way to send a prompt into one.
32
29
  *
33
- * `sessions` only lists sessions where server-side process detection has
34
- * *confirmed* a running coding agent (editors and plain shells are excluded,
35
- * as are optimistic just-launched tags): every listed session is one whose
36
- * TUI can meaningfully receive pasted prompt text. `sendPrompt` re-validates
37
- * against the server before writing, since pasting prose into a shell prompt
38
- * would execute it.
30
+ * Only sessions with a detection-*confirmed* running agent are listed — never
31
+ * optimistic launch tags: pasted prompt text must land in an agent's TUI, not
32
+ * a shell prompt where it would be executed.
39
33
  */
40
34
  export interface IAgentTerminals {
41
35
  /**
@@ -47,20 +41,15 @@ export interface IAgentTerminals {
47
41
  */
48
42
  readonly changed: ISignal<IAgentTerminals, void>;
49
43
  /**
50
- * Paste `prompt` into the named session's terminal and press Enter.
51
- *
52
- * Delivery is deliberately background: the text is written straight to
53
- * the session's websocket, bracketed-paste-wrapped so a multi-line prompt
54
- * arrives as one block in the agent's input box, without revealing or
55
- * focusing the terminal's tab — the user keeps working where they are,
56
- * and the agent CLIs queue the prompt themselves when they are busy.
57
- * Rejects when the session is gone or no agent is running in it anymore.
44
+ * Paste `prompt` (bracketed-paste-wrapped) into the named session and press
45
+ * Enter, writing straight to its websocket without revealing or focusing
46
+ * its tab. Rejects when the session is gone or no agent runs in it anymore.
58
47
  */
59
48
  sendPrompt(name: string, prompt: string): Promise<void>;
60
49
  }
61
50
  /**
62
51
  * DI token for {@link IAgentTerminals}. Provided by `xtralab:terminals`;
63
- * consumed — optionally, so each side works without the other — by
64
- * `xtralab:ask-agent` to offer running agent terminals as prompt targets.
52
+ * consumed optionally by `xtralab:ask-agent`, so each side works without
53
+ * the other.
65
54
  */
66
55
  export declare const IAgentTerminals: Token<IAgentTerminals>;
@@ -1,7 +1,7 @@
1
1
  import { Token } from '@lumino/coreutils';
2
2
  /**
3
3
  * DI token for {@link IAgentTerminals}. Provided by `xtralab:terminals`;
4
- * consumed — optionally, so each side works without the other — by
5
- * `xtralab:ask-agent` to offer running agent terminals as prompt targets.
4
+ * consumed optionally by `xtralab:ask-agent`, so each side works without
5
+ * the other.
6
6
  */
7
7
  export const IAgentTerminals = new Token('xtralab:IAgentTerminals', 'The running terminal sessions with a detected coding agent, and a way to send a prompt into one.');