lazy-gravity 0.6.2 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -229,8 +229,10 @@ function parseRunCommandCustomId(customId) {
229
229
  return null;
230
230
  }
231
231
  /** Initialize the CDP bridge (lazy connection: pool creation only) */
232
- function initCdpBridge(autoApproveDefault) {
232
+ function initCdpBridge(autoApproveDefault, accountPorts = {}, accountUserDataDirs = {}) {
233
233
  const pool = new cdpConnectionPool_1.CdpConnectionPool({
234
+ accountPorts,
235
+ accountUserDataDirs,
234
236
  cdpCallTimeout: 15000,
235
237
  // Keep CDP reconnection lazy: do not reopen windows in background.
236
238
  // Reconnection is triggered when the next chat/template message is sent.
@@ -247,6 +249,7 @@ function initCdpBridge(autoApproveDefault) {
247
249
  lastActiveChannel: null,
248
250
  approvalChannelByWorkspace: new Map(),
249
251
  approvalChannelBySession: new Map(),
252
+ selectedAccountByChannel: new Map(),
250
253
  };
251
254
  }
252
255
  /**
@@ -263,8 +266,8 @@ function getCurrentCdp(bridge) {
263
266
  * Helper to start an approval detector for each workspace.
264
267
  * Does nothing if a detector for the same workspace is already running.
265
268
  */
266
- function ensureApprovalDetector(bridge, cdp, projectName) {
267
- const existing = bridge.pool.getApprovalDetector(projectName);
269
+ function ensureApprovalDetector(bridge, cdp, projectName, accountName = 'default') {
270
+ const existing = bridge.pool.getApprovalDetector(projectName, accountName);
268
271
  if (existing && existing.isActive())
269
272
  return;
270
273
  // Track the most recent notification for auto-disable on resolve.
@@ -327,15 +330,15 @@ function ensureApprovalDetector(bridge, cdp, projectName) {
327
330
  },
328
331
  });
329
332
  detector.start();
330
- bridge.pool.registerApprovalDetector(projectName, detector);
333
+ bridge.pool.registerApprovalDetector(projectName, detector, accountName);
331
334
  logger_1.logger.debug(`[ApprovalDetector:${projectName}] Started approval button detection`);
332
335
  }
333
336
  /**
334
337
  * Helper to start a planning detector for each workspace.
335
338
  * Does nothing if a detector for the same workspace is already running.
336
339
  */
337
- function ensurePlanningDetector(bridge, cdp, projectName) {
338
- const existing = bridge.pool.getPlanningDetector(projectName);
340
+ function ensurePlanningDetector(bridge, cdp, projectName, accountName = 'default') {
341
+ const existing = bridge.pool.getPlanningDetector(projectName, accountName);
339
342
  if (existing && existing.isActive())
340
343
  return;
341
344
  // Track the most recent planning notification for auto-disable on resolve.
@@ -387,15 +390,15 @@ function ensurePlanningDetector(bridge, cdp, projectName) {
387
390
  },
388
391
  });
389
392
  detector.start();
390
- bridge.pool.registerPlanningDetector(projectName, detector);
393
+ bridge.pool.registerPlanningDetector(projectName, detector, accountName);
391
394
  logger_1.logger.debug(`[PlanningDetector:${projectName}] Started planning button detection`);
392
395
  }
393
396
  /**
394
397
  * Helper to start an error popup detector for each workspace.
395
398
  * Does nothing if a detector for the same workspace is already running.
396
399
  */
397
- function ensureErrorPopupDetector(bridge, cdp, projectName) {
398
- const existing = bridge.pool.getErrorPopupDetector(projectName);
400
+ function ensureErrorPopupDetector(bridge, cdp, projectName, accountName = 'default') {
401
+ const existing = bridge.pool.getErrorPopupDetector(projectName, accountName);
399
402
  if (existing && existing.isActive())
400
403
  return;
401
404
  // Track the most recent error notification for auto-disable on resolve.
@@ -443,7 +446,7 @@ function ensureErrorPopupDetector(bridge, cdp, projectName) {
443
446
  },
444
447
  });
445
448
  detector.start();
446
- bridge.pool.registerErrorPopupDetector(projectName, detector);
449
+ bridge.pool.registerErrorPopupDetector(projectName, detector, accountName);
447
450
  logger_1.logger.debug(`[ErrorPopupDetector:${projectName}] Started error popup detection`);
448
451
  }
449
452
  /**
@@ -451,8 +454,8 @@ function ensureErrorPopupDetector(bridge, cdp, projectName) {
451
454
  * Detects "Run command?" confirmation dialogs and forwards them to Discord.
452
455
  * Does nothing if a detector for the same workspace is already running.
453
456
  */
454
- function ensureRunCommandDetector(bridge, cdp, projectName) {
455
- const existing = bridge.pool.getRunCommandDetector(projectName);
457
+ function ensureRunCommandDetector(bridge, cdp, projectName, accountName = 'default') {
458
+ const existing = bridge.pool.getRunCommandDetector(projectName, accountName);
456
459
  if (existing && existing.isActive())
457
460
  return;
458
461
  let lastNotification = null;
@@ -511,7 +514,7 @@ function ensureRunCommandDetector(bridge, cdp, projectName) {
511
514
  },
512
515
  });
513
516
  detector.start();
514
- bridge.pool.registerRunCommandDetector(projectName, detector);
517
+ bridge.pool.registerRunCommandDetector(projectName, detector, accountName);
515
518
  logger_1.logger.debug(`[RunCommandDetector:${projectName}] Started run command detection`);
516
519
  }
517
520
  /**
@@ -520,16 +523,18 @@ function ensureRunCommandDetector(bridge, cdp, projectName) {
520
523
  * and mirrors them to a Discord channel.
521
524
  * Does nothing if a detector for the same workspace is already running.
522
525
  */
523
- function ensureUserMessageDetector(bridge, cdp, projectName, onUserMessage) {
524
- const existing = bridge.pool.getUserMessageDetector(projectName);
525
- if (existing && existing.isActive())
526
+ function ensureUserMessageDetector(bridge, cdp, projectName, onUserMessage, accountName = 'default') {
527
+ const existing = bridge.pool.getUserMessageDetector(projectName, accountName);
528
+ if (existing && existing.isActive()) {
529
+ existing.on('message', onUserMessage);
526
530
  return;
531
+ }
527
532
  const detector = new userMessageDetector_1.UserMessageDetector({
528
533
  cdpService: cdp,
529
534
  pollIntervalMs: 2000,
530
- onUserMessage,
531
535
  });
536
+ detector.on('message', onUserMessage);
532
537
  detector.start();
533
- bridge.pool.registerUserMessageDetector(projectName, detector);
538
+ bridge.pool.registerUserMessageDetector(projectName, detector, accountName);
534
539
  logger_1.logger.debug(`[UserMessageDetector:${projectName}] Started user message detection`);
535
540
  }
@@ -4,15 +4,15 @@ exports.CdpConnectionPool = void 0;
4
4
  const logger_1 = require("../utils/logger");
5
5
  const pathUtils_1 = require("../utils/pathUtils");
6
6
  const cdpService_1 = require("./cdpService");
7
+ function buildConnectionKey(projectName, accountName) {
8
+ return `${accountName}::${projectName}`;
9
+ }
7
10
  /**
8
- * Pool that manages independent CdpService instances per workspace.
9
- *
10
- * Each workspace owns its own WebSocket / contexts / pendingCalls, so
11
- * switching to workspace B while workspace A's ResponseMonitor is polling
12
- * does not destroy A's WebSocket.
11
+ * Pool that manages independent CdpService instances per workspace/account pair.
13
12
  */
14
13
  class CdpConnectionPool {
15
14
  connections = new Map();
15
+ workspaceToAccount = new Map();
16
16
  approvalDetectors = new Map();
17
17
  errorPopupDetectors = new Map();
18
18
  planningDetectors = new Map();
@@ -23,245 +23,172 @@ class CdpConnectionPool {
23
23
  constructor(cdpOptions = {}) {
24
24
  this.cdpOptions = cdpOptions;
25
25
  }
26
- /**
27
- * Get a CdpService for the given workspace path.
28
- * Creates a new connection and caches it if not already connected.
29
- * Prevents concurrent connections via Promise locking.
30
- *
31
- * @param workspacePath Full path of the workspace
32
- * @returns Connected CdpService
33
- */
34
- async getOrConnect(workspacePath) {
26
+ resolveAccountName(projectName, accountName, explicitSelection = false) {
27
+ if (explicitSelection) {
28
+ return accountName;
29
+ }
30
+ if (accountName !== 'default')
31
+ return accountName;
32
+ return this.workspaceToAccount.get(projectName) || accountName;
33
+ }
34
+ async getOrConnect(workspacePath, selection) {
35
35
  const projectName = this.extractProjectName(workspacePath);
36
- // Return existing connection if available
37
- const existing = this.connections.get(projectName);
36
+ const explicitSelection = typeof selection?.name === 'string';
37
+ const accountName = selection?.name || this.workspaceToAccount.get(projectName) || 'default';
38
+ const effectiveAccount = this.resolveAccountName(projectName, accountName, explicitSelection);
39
+ const key = buildConnectionKey(projectName, effectiveAccount);
40
+ const existing = this.connections.get(key);
38
41
  if (existing && existing.isConnected()) {
39
- // Re-validate that the still-open window is actually bound to this workspace.
40
42
  await existing.discoverAndConnectForWorkspace(workspacePath);
41
43
  return existing;
42
44
  }
43
- // Wait for the pending connection promise if one exists (prevents concurrent connections)
44
- const pending = this.connectingPromises.get(projectName);
45
+ const pending = this.connectingPromises.get(key);
45
46
  if (pending) {
46
47
  return pending;
47
48
  }
48
- // Start a new connection
49
- const connectPromise = this.createAndConnect(workspacePath, projectName);
50
- this.connectingPromises.set(projectName, connectPromise);
49
+ const connectPromise = this.createAndConnect(workspacePath, projectName, effectiveAccount);
50
+ this.connectingPromises.set(key, connectPromise);
51
51
  try {
52
- const cdp = await connectPromise;
53
- return cdp;
52
+ return await connectPromise;
54
53
  }
55
54
  finally {
56
- this.connectingPromises.delete(projectName);
55
+ this.connectingPromises.delete(key);
56
+ this.workspaceToAccount.set(projectName, effectiveAccount);
57
57
  }
58
58
  }
59
- /**
60
- * Get a connected CdpService (read-only).
61
- * Returns null if not connected.
62
- */
63
- getConnected(projectName) {
64
- const cdp = this.connections.get(projectName);
59
+ getConnected(projectName, accountName = 'default') {
60
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
61
+ const cdp = this.connections.get(buildConnectionKey(projectName, effectiveAccount));
65
62
  if (cdp && cdp.isConnected()) {
66
63
  return cdp;
67
64
  }
68
65
  return null;
69
66
  }
70
- /**
71
- * Disconnect the specified workspace.
72
- */
73
- disconnectWorkspace(projectName) {
74
- const cdp = this.connections.get(projectName);
67
+ disconnectWorkspace(projectName, accountName = 'default') {
68
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
69
+ const key = buildConnectionKey(projectName, effectiveAccount);
70
+ const cdp = this.connections.get(key);
75
71
  if (cdp) {
76
72
  cdp.disconnect().catch((err) => {
77
- logger_1.logger.error(`[CdpConnectionPool] Error while disconnecting ${projectName}:`, err);
73
+ logger_1.logger.error(`[CdpConnectionPool] Error while disconnecting ${key}:`, err);
78
74
  });
79
- this.connections.delete(projectName);
80
- }
81
- const detector = this.approvalDetectors.get(projectName);
82
- if (detector) {
83
- detector.stop();
84
- this.approvalDetectors.delete(projectName);
85
- }
86
- const errorPopupDetector = this.errorPopupDetectors.get(projectName);
87
- if (errorPopupDetector) {
88
- errorPopupDetector.stop();
89
- this.errorPopupDetectors.delete(projectName);
90
- }
91
- const planningDetector = this.planningDetectors.get(projectName);
92
- if (planningDetector) {
93
- planningDetector.stop();
94
- this.planningDetectors.delete(projectName);
95
- }
96
- const runCmdDetector = this.runCommandDetectors.get(projectName);
97
- if (runCmdDetector) {
98
- runCmdDetector.stop();
99
- this.runCommandDetectors.delete(projectName);
100
- }
101
- const userMsgDetector = this.userMessageDetectors.get(projectName);
102
- if (userMsgDetector) {
103
- userMsgDetector.stop();
104
- this.userMessageDetectors.delete(projectName);
105
- }
75
+ this.connections.delete(key);
76
+ }
77
+ this.approvalDetectors.get(key)?.stop();
78
+ this.approvalDetectors.delete(key);
79
+ this.errorPopupDetectors.get(key)?.stop();
80
+ this.errorPopupDetectors.delete(key);
81
+ this.planningDetectors.get(key)?.stop();
82
+ this.planningDetectors.delete(key);
83
+ this.runCommandDetectors.get(key)?.stop();
84
+ this.runCommandDetectors.delete(key);
85
+ this.userMessageDetectors.get(key)?.stop();
86
+ this.userMessageDetectors.delete(key);
106
87
  }
107
- /**
108
- * Disconnect all workspace connections.
109
- */
110
88
  disconnectAll() {
111
- for (const projectName of [...this.connections.keys()]) {
112
- this.disconnectWorkspace(projectName);
113
- }
114
- }
115
- /**
116
- * Register an approval detector for a workspace.
117
- */
118
- registerApprovalDetector(projectName, detector) {
119
- // Stop existing detector
120
- const existing = this.approvalDetectors.get(projectName);
121
- if (existing && existing.isActive()) {
122
- existing.stop();
123
- }
124
- this.approvalDetectors.set(projectName, detector);
125
- }
126
- /**
127
- * Get the approval detector for a workspace.
128
- */
129
- getApprovalDetector(projectName) {
130
- return this.approvalDetectors.get(projectName);
131
- }
132
- /**
133
- * Register an error popup detector for a workspace.
134
- */
135
- registerErrorPopupDetector(projectName, detector) {
136
- // Stop existing detector
137
- const existing = this.errorPopupDetectors.get(projectName);
138
- if (existing && existing.isActive()) {
139
- existing.stop();
140
- }
141
- this.errorPopupDetectors.set(projectName, detector);
142
- }
143
- /**
144
- * Get the error popup detector for a workspace.
145
- */
146
- getErrorPopupDetector(projectName) {
147
- return this.errorPopupDetectors.get(projectName);
148
- }
149
- /**
150
- * Register a planning detector for a workspace.
151
- */
152
- registerPlanningDetector(projectName, detector) {
153
- // Stop existing detector
154
- const existing = this.planningDetectors.get(projectName);
155
- if (existing && existing.isActive()) {
156
- existing.stop();
157
- }
158
- this.planningDetectors.set(projectName, detector);
159
- }
160
- /**
161
- * Get the planning detector for a workspace.
162
- */
163
- getPlanningDetector(projectName) {
164
- return this.planningDetectors.get(projectName);
165
- }
166
- /**
167
- * Register a run command detector for a workspace.
168
- */
169
- registerRunCommandDetector(projectName, detector) {
170
- const existing = this.runCommandDetectors.get(projectName);
171
- if (existing && existing.isActive()) {
172
- existing.stop();
173
- }
174
- this.runCommandDetectors.set(projectName, detector);
175
- }
176
- /**
177
- * Get the run command detector for a workspace.
178
- */
179
- getRunCommandDetector(projectName) {
180
- return this.runCommandDetectors.get(projectName);
181
- }
182
- /**
183
- * Register a user message detector for a workspace.
184
- */
185
- registerUserMessageDetector(projectName, detector) {
186
- const existing = this.userMessageDetectors.get(projectName);
187
- if (existing && existing.isActive()) {
188
- existing.stop();
189
- }
190
- this.userMessageDetectors.set(projectName, detector);
89
+ for (const key of [...this.connections.keys()]) {
90
+ const [accountName, projectName] = key.split('::');
91
+ this.disconnectWorkspace(projectName, accountName);
92
+ }
93
+ }
94
+ registerApprovalDetector(projectName, detector, accountName = 'default') {
95
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
96
+ const key = buildConnectionKey(projectName, effectiveAccount);
97
+ this.approvalDetectors.get(key)?.stop();
98
+ this.approvalDetectors.set(key, detector);
99
+ }
100
+ getApprovalDetector(projectName, accountName = 'default') {
101
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
102
+ return this.approvalDetectors.get(buildConnectionKey(projectName, effectiveAccount));
103
+ }
104
+ registerErrorPopupDetector(projectName, detector, accountName = 'default') {
105
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
106
+ const key = buildConnectionKey(projectName, effectiveAccount);
107
+ this.errorPopupDetectors.get(key)?.stop();
108
+ this.errorPopupDetectors.set(key, detector);
109
+ }
110
+ getErrorPopupDetector(projectName, accountName = 'default') {
111
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
112
+ return this.errorPopupDetectors.get(buildConnectionKey(projectName, effectiveAccount));
113
+ }
114
+ registerPlanningDetector(projectName, detector, accountName = 'default') {
115
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
116
+ const key = buildConnectionKey(projectName, effectiveAccount);
117
+ this.planningDetectors.get(key)?.stop();
118
+ this.planningDetectors.set(key, detector);
119
+ }
120
+ getPlanningDetector(projectName, accountName = 'default') {
121
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
122
+ return this.planningDetectors.get(buildConnectionKey(projectName, effectiveAccount));
123
+ }
124
+ registerRunCommandDetector(projectName, detector, accountName = 'default') {
125
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
126
+ const key = buildConnectionKey(projectName, effectiveAccount);
127
+ this.runCommandDetectors.get(key)?.stop();
128
+ this.runCommandDetectors.set(key, detector);
129
+ }
130
+ getRunCommandDetector(projectName, accountName = 'default') {
131
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
132
+ return this.runCommandDetectors.get(buildConnectionKey(projectName, effectiveAccount));
133
+ }
134
+ registerUserMessageDetector(projectName, detector, accountName = 'default') {
135
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
136
+ const key = buildConnectionKey(projectName, effectiveAccount);
137
+ this.userMessageDetectors.get(key)?.stop();
138
+ this.userMessageDetectors.set(key, detector);
139
+ }
140
+ getUserMessageDetector(projectName, accountName = 'default') {
141
+ const effectiveAccount = this.resolveAccountName(projectName, accountName);
142
+ return this.userMessageDetectors.get(buildConnectionKey(projectName, effectiveAccount));
143
+ }
144
+ setPreferredAccountForWorkspace(workspacePath, accountName) {
145
+ const projectName = this.extractProjectName(workspacePath);
146
+ this.workspaceToAccount.set(projectName, accountName);
191
147
  }
192
- /**
193
- * Get the user message detector for a workspace.
194
- */
195
- getUserMessageDetector(projectName) {
196
- return this.userMessageDetectors.get(projectName);
148
+ getPreferredAccountForWorkspace(workspacePath) {
149
+ const projectName = this.extractProjectName(workspacePath);
150
+ return this.workspaceToAccount.get(projectName) ?? null;
197
151
  }
198
- /**
199
- * Return a list of workspace names with active connections.
200
- */
201
152
  getActiveWorkspaceNames() {
202
- const active = [];
203
- for (const [name, cdp] of this.connections) {
204
- if (cdp.isConnected()) {
205
- active.push(name);
206
- }
153
+ const active = new Set();
154
+ for (const [key, cdp] of this.connections) {
155
+ if (!cdp.isConnected())
156
+ continue;
157
+ const [, projectName] = key.split('::');
158
+ active.add(projectName || key);
207
159
  }
208
- return active;
160
+ return [...active];
209
161
  }
210
- /**
211
- * Extract the project name from a workspace path.
212
- */
213
162
  extractProjectName(workspacePath) {
214
163
  return (0, pathUtils_1.extractProjectNameFromPath)(workspacePath) || workspacePath;
215
164
  }
216
- /**
217
- * Create a new CdpService and connect to the workspace.
218
- */
219
- async createAndConnect(workspacePath, projectName) {
220
- // Disconnect old connection if exists
221
- const old = this.connections.get(projectName);
165
+ async createAndConnect(workspacePath, projectName, accountName) {
166
+ const key = buildConnectionKey(projectName, accountName);
167
+ const old = this.connections.get(key);
222
168
  if (old) {
223
169
  await old.disconnect().catch(() => { });
224
- this.connections.delete(projectName);
170
+ this.connections.delete(key);
225
171
  }
226
- const cdp = new cdpService_1.CdpService(this.cdpOptions);
227
- // Auto-cleanup on disconnect
228
- cdp.on('disconnected', () => {
229
- logger_1.logger.error(`[CdpConnectionPool] Workspace "${projectName}" disconnected`);
230
- // Only remove from Map when reconnection fails
231
- // (CdpService attempts reconnection internally, so we don't remove here)
172
+ const cdp = new cdpService_1.CdpService({
173
+ ...this.cdpOptions,
174
+ accountName,
232
175
  });
233
176
  cdp.on('reconnectFailed', () => {
234
- logger_1.logger.error(`[CdpConnectionPool] Reconnection failed for workspace "${projectName}". Removing from pool`);
235
- this.connections.delete(projectName);
236
- const detector = this.approvalDetectors.get(projectName);
237
- if (detector) {
238
- detector.stop();
239
- this.approvalDetectors.delete(projectName);
240
- }
241
- const errorDetector = this.errorPopupDetectors.get(projectName);
242
- if (errorDetector) {
243
- errorDetector.stop();
244
- this.errorPopupDetectors.delete(projectName);
245
- }
246
- const planDetector = this.planningDetectors.get(projectName);
247
- if (planDetector) {
248
- planDetector.stop();
249
- this.planningDetectors.delete(projectName);
250
- }
251
- const runCmdDetector = this.runCommandDetectors.get(projectName);
252
- if (runCmdDetector) {
253
- runCmdDetector.stop();
254
- this.runCommandDetectors.delete(projectName);
255
- }
256
- const userMsgDetector = this.userMessageDetectors.get(projectName);
257
- if (userMsgDetector) {
258
- userMsgDetector.stop();
259
- this.userMessageDetectors.delete(projectName);
260
- }
177
+ logger_1.logger.error(`[CdpConnectionPool] Reconnection failed for workspace "${key}". Removing from pool`);
178
+ this.connections.delete(key);
179
+ this.approvalDetectors.get(key)?.stop();
180
+ this.approvalDetectors.delete(key);
181
+ this.errorPopupDetectors.get(key)?.stop();
182
+ this.errorPopupDetectors.delete(key);
183
+ this.planningDetectors.get(key)?.stop();
184
+ this.planningDetectors.delete(key);
185
+ this.runCommandDetectors.get(key)?.stop();
186
+ this.runCommandDetectors.delete(key);
187
+ this.userMessageDetectors.get(key)?.stop();
188
+ this.userMessageDetectors.delete(key);
261
189
  });
262
- // Connect to the workspace
263
190
  await cdp.discoverAndConnectForWorkspace(workspacePath);
264
- this.connections.set(projectName, cdp);
191
+ this.connections.set(key, cdp);
265
192
  return cdp;
266
193
  }
267
194
  }
@@ -1912,6 +1912,8 @@ class CdpService extends events_1.EventEmitter {
1912
1912
  '[role="button"]',
1913
1913
  'div.cursor-pointer',
1914
1914
  'div[class*="cursor-pointer"]',
1915
+ 'span[class*="select-none"]',
1916
+ 'span[class*="text-xs"]',
1915
1917
  ];
1916
1918
  const getScopes = () => {
1917
1919
  const scopes = [document];
@@ -1956,6 +1958,8 @@ class CdpService extends events_1.EventEmitter {
1956
1958
  '[role="button"]',
1957
1959
  'div.cursor-pointer',
1958
1960
  'div[class*="cursor-pointer"]',
1961
+ 'span[class*="select-none"]',
1962
+ 'span[class*="overflow-hidden"]',
1959
1963
  ];
1960
1964
 
1961
1965
  let models = collectModels();
@@ -2070,7 +2074,8 @@ class CdpService extends events_1.EventEmitter {
2070
2074
  };
2071
2075
  const candidates = Array.from(document.querySelectorAll(
2072
2076
  '[role="option"], [role="menuitem"], [role="combobox"], [aria-selected], [aria-checked], ' +
2073
- '[aria-current], button, [role="button"], div.cursor-pointer, div[class*="cursor-pointer"]'
2077
+ '[aria-current], button, [role="button"], div.cursor-pointer, div[class*="cursor-pointer"], ' +
2078
+ 'span[class*="select-none"], span[class*="text-xs"]'
2074
2079
  ))
2075
2080
  .filter(isVisible)
2076
2081
  .map((el) => ({ el, label: getLabel(el), score: getScore(el) }))
@@ -2118,10 +2123,10 @@ class CdpService extends events_1.EventEmitter {
2118
2123
  if (!this.isConnectedFlag || !this.ws) {
2119
2124
  await this.reconnectOnDemand();
2120
2125
  }
2121
- // DOM manipulation script: based on actual Antigravity UI DOM structure
2122
- // Model list uses div.cursor-pointer elements with class 'px-2 py-1 flex items-center justify-between'
2123
- // Currently selected has 'bg-gray-500/20', others have 'hover:bg-gray-500/10'
2124
- // textContent may have "New" suffix
2126
+ // DOM manipulation script: adaptive Antigravity UI model picker
2127
+ // Legacy (<v1.107): div.cursor-pointer with class 'px-2 py-1 flex items-center justify-between'
2128
+ // v1.107+: span elements with classes 'select-none', 'text-xs', 'overflow-hidden'
2129
+ // Selection detected via ARIA attributes, data-state, or bg-gray-500/20 class
2125
2130
  const safeModel = JSON.stringify(modelName);
2126
2131
  const expression = `(async () => {
2127
2132
  const targetModel = ${safeModel};
@@ -2160,6 +2165,8 @@ class CdpService extends events_1.EventEmitter {
2160
2165
  '[role="button"]',
2161
2166
  'div.cursor-pointer',
2162
2167
  'div[class*="cursor-pointer"]',
2168
+ 'span[class*="select-none"]',
2169
+ 'span[class*="text-xs"]',
2163
2170
  ];
2164
2171
  const triggerSelectors = [
2165
2172
  '[role="combobox"]',
@@ -2170,6 +2177,8 @@ class CdpService extends events_1.EventEmitter {
2170
2177
  '[role="button"]',
2171
2178
  'div.cursor-pointer',
2172
2179
  'div[class*="cursor-pointer"]',
2180
+ 'span[class*="select-none"]',
2181
+ 'span[class*="overflow-hidden"]',
2173
2182
  ];
2174
2183
  const scopeSelectors = [
2175
2184
  '[role="dialog"]',