lazy-gravity 0.6.1 → 0.7.0
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.
- package/dist/bot/index.js +416 -45
- package/dist/bot/telegramCommands.js +175 -48
- package/dist/bot/telegramJoinCommand.js +170 -0
- package/dist/bot/telegramMessageHandler.js +27 -7
- package/dist/bot/telegramProjectCommand.js +71 -18
- package/dist/bot/telegramStartupTarget.js +54 -0
- package/dist/commands/chatCommandHandler.js +8 -12
- package/dist/commands/joinCommandHandler.js +16 -10
- package/dist/commands/registerSlashCommands.js +13 -1
- package/dist/commands/workspaceCommandHandler.js +22 -7
- package/dist/database/accountPreferenceRepository.js +29 -0
- package/dist/database/channelPreferenceRepository.js +29 -0
- package/dist/database/chatSessionRepository.js +66 -3
- package/dist/database/telegramBindingRepository.js +13 -0
- package/dist/events/interactionCreateHandler.js +194 -13
- package/dist/events/messageCreateHandler.js +103 -7
- package/dist/handlers/accountSelectAction.js +45 -0
- package/dist/handlers/modelButtonAction.js +13 -0
- package/dist/services/cdpBridgeManager.js +23 -18
- package/dist/services/cdpConnectionPool.js +133 -206
- package/dist/services/chatSessionService.js +199 -16
- package/dist/services/responseMonitor.js +235 -48
- package/dist/services/userMessageDetector.js +4 -4
- package/dist/ui/accountUi.js +60 -0
- package/dist/utils/accountUtils.js +36 -0
- package/dist/utils/cdpPorts.js +97 -2
- package/dist/utils/configLoader.js +14 -0
- package/package.json +1 -1
|
@@ -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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
37
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
this.connectingPromises.set(projectName, connectPromise);
|
|
49
|
+
const connectPromise = this.createAndConnect(workspacePath, projectName, effectiveAccount);
|
|
50
|
+
this.connectingPromises.set(key, connectPromise);
|
|
51
51
|
try {
|
|
52
|
-
|
|
53
|
-
return cdp;
|
|
52
|
+
return await connectPromise;
|
|
54
53
|
}
|
|
55
54
|
finally {
|
|
56
|
-
this.connectingPromises.delete(
|
|
55
|
+
this.connectingPromises.delete(key);
|
|
56
|
+
this.workspaceToAccount.set(projectName, effectiveAccount);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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 ${
|
|
73
|
+
logger_1.logger.error(`[CdpConnectionPool] Error while disconnecting ${key}:`, err);
|
|
78
74
|
});
|
|
79
|
-
this.connections.delete(
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
this.approvalDetectors.
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return this.
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
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 [
|
|
204
|
-
if (cdp.isConnected())
|
|
205
|
-
|
|
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
|
-
|
|
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(
|
|
170
|
+
this.connections.delete(key);
|
|
225
171
|
}
|
|
226
|
-
const cdp = new cdpService_1.CdpService(
|
|
227
|
-
|
|
228
|
-
|
|
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 "${
|
|
235
|
-
this.connections.delete(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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(
|
|
191
|
+
this.connections.set(key, cdp);
|
|
265
192
|
return cdp;
|
|
266
193
|
}
|
|
267
194
|
}
|