dominus-cli 0.5.9 → 0.6.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/index.js +234 -57
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +204 -49
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -252,7 +252,12 @@ var init_ws_server = __esm({
|
|
|
252
252
|
init_protocol();
|
|
253
253
|
DominusServer = class extends EventEmitter {
|
|
254
254
|
wss = null;
|
|
255
|
-
|
|
255
|
+
/** All connected Studio instances, keyed by placeId (0 for unknown) */
|
|
256
|
+
studioClients = /* @__PURE__ */ new Map();
|
|
257
|
+
/** Reverse lookup: ws → placeId */
|
|
258
|
+
wsToPlaceId = /* @__PURE__ */ new Map();
|
|
259
|
+
/** Which placeId to target. 0 = auto-select if only one is connected. */
|
|
260
|
+
activePlaceId = 0;
|
|
256
261
|
controllers = /* @__PURE__ */ new Set();
|
|
257
262
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
258
263
|
relayRequests = /* @__PURE__ */ new Map();
|
|
@@ -301,7 +306,9 @@ var init_ws_server = __esm({
|
|
|
301
306
|
this.addController(ws);
|
|
302
307
|
ws.send(serializeMessage(createMessage("controller:welcome", {
|
|
303
308
|
studioConnected: this.isConnected(),
|
|
304
|
-
port: this.port
|
|
309
|
+
port: this.port,
|
|
310
|
+
connections: this.listConnections(),
|
|
311
|
+
activePlaceId: this.activePlaceId
|
|
305
312
|
})));
|
|
306
313
|
return;
|
|
307
314
|
}
|
|
@@ -309,7 +316,7 @@ var init_ws_server = __esm({
|
|
|
309
316
|
if (this.controllers.has(ws)) {
|
|
310
317
|
this.handleControllerMessage(ws, msg);
|
|
311
318
|
} else {
|
|
312
|
-
this.handleStudioMessage(msg);
|
|
319
|
+
this.handleStudioMessage(ws, msg);
|
|
313
320
|
}
|
|
314
321
|
} catch (err) {
|
|
315
322
|
this.emit("server:error", err);
|
|
@@ -321,14 +328,22 @@ var init_ws_server = __esm({
|
|
|
321
328
|
for (const [id, controllerWs] of this.relayRequests) {
|
|
322
329
|
if (controllerWs === ws) this.relayRequests.delete(id);
|
|
323
330
|
}
|
|
324
|
-
} else
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
this.
|
|
331
|
+
} else {
|
|
332
|
+
const placeId = this.wsToPlaceId.get(ws);
|
|
333
|
+
if (placeId !== void 0) {
|
|
334
|
+
const conn = this.studioClients.get(placeId);
|
|
335
|
+
this.studioClients.delete(placeId);
|
|
336
|
+
this.wsToPlaceId.delete(ws);
|
|
337
|
+
this.emit("studio:disconnected", { placeId, placeName: conn?.placeName });
|
|
338
|
+
this.broadcastToControllers("studio:disconnected", { placeId, placeName: conn?.placeName });
|
|
339
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
340
|
+
clearTimeout(pending.timer);
|
|
341
|
+
pending.reject(new Error(`Studio disconnected (place ${placeId})`));
|
|
342
|
+
this.pendingRequests.delete(id);
|
|
343
|
+
}
|
|
344
|
+
if (this.activePlaceId === placeId) {
|
|
345
|
+
this.activePlaceId = 0;
|
|
346
|
+
}
|
|
332
347
|
}
|
|
333
348
|
}
|
|
334
349
|
});
|
|
@@ -337,19 +352,24 @@ var init_ws_server = __esm({
|
|
|
337
352
|
});
|
|
338
353
|
}
|
|
339
354
|
setStudioClient(ws, msg) {
|
|
340
|
-
if (this.studioClient) {
|
|
341
|
-
this.studioClient.ws.close();
|
|
342
|
-
}
|
|
343
355
|
const payload = msg.payload;
|
|
344
|
-
|
|
356
|
+
const placeId = payload.placeId ?? 0;
|
|
357
|
+
const existing = this.studioClients.get(placeId);
|
|
358
|
+
if (existing && existing.ws !== ws) {
|
|
359
|
+
existing.ws.close();
|
|
360
|
+
this.wsToPlaceId.delete(existing.ws);
|
|
361
|
+
}
|
|
362
|
+
const conn = {
|
|
345
363
|
ws,
|
|
346
364
|
connectedAt: Date.now(),
|
|
347
365
|
studioVersion: payload.studioVersion,
|
|
348
|
-
placeId
|
|
366
|
+
placeId,
|
|
349
367
|
placeName: payload.placeName
|
|
350
368
|
};
|
|
351
|
-
this.
|
|
352
|
-
this.
|
|
369
|
+
this.studioClients.set(placeId, conn);
|
|
370
|
+
this.wsToPlaceId.set(ws, placeId);
|
|
371
|
+
this.emit("studio:connected", { ...payload, placeId });
|
|
372
|
+
this.broadcastToControllers("studio:connected", { ...payload, placeId });
|
|
353
373
|
}
|
|
354
374
|
addController(ws) {
|
|
355
375
|
this.controllers.add(ws);
|
|
@@ -364,25 +384,30 @@ var init_ws_server = __esm({
|
|
|
364
384
|
}
|
|
365
385
|
}
|
|
366
386
|
handleControllerMessage(controllerWs, msg) {
|
|
367
|
-
|
|
387
|
+
const target = this.resolveTarget();
|
|
388
|
+
if (!target || target.ws.readyState !== WebSocket.OPEN) {
|
|
368
389
|
controllerWs.send(serializeMessage({
|
|
369
390
|
id: msg.id,
|
|
370
391
|
type: StudioMsg.RESPONSE,
|
|
371
|
-
payload: { error:
|
|
392
|
+
payload: { error: this.getTargetError() },
|
|
372
393
|
ts: Date.now()
|
|
373
394
|
}));
|
|
374
395
|
return;
|
|
375
396
|
}
|
|
376
397
|
this.relayRequests.set(msg.id, controllerWs);
|
|
377
|
-
|
|
398
|
+
target.ws.send(serializeMessage(msg));
|
|
378
399
|
}
|
|
379
|
-
handleStudioMessage(msg) {
|
|
400
|
+
handleStudioMessage(ws, msg) {
|
|
380
401
|
if (msg.type === StudioMsg.CONNECTED) {
|
|
381
402
|
const payload = msg.payload;
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
403
|
+
const placeId = this.wsToPlaceId.get(ws);
|
|
404
|
+
if (placeId !== void 0) {
|
|
405
|
+
const conn = this.studioClients.get(placeId);
|
|
406
|
+
if (conn) {
|
|
407
|
+
conn.studioVersion = payload.studioVersion;
|
|
408
|
+
conn.placeId = payload.placeId;
|
|
409
|
+
conn.placeName = payload.placeName;
|
|
410
|
+
}
|
|
386
411
|
}
|
|
387
412
|
this.emit("studio:connected", payload);
|
|
388
413
|
this.broadcastToControllers("studio:connected", payload);
|
|
@@ -407,10 +432,35 @@ var init_ws_server = __esm({
|
|
|
407
432
|
this.emit("message", msg);
|
|
408
433
|
this.broadcastToControllers(msg.type, msg.payload);
|
|
409
434
|
}
|
|
435
|
+
/** Resolve which Studio connection to target */
|
|
436
|
+
resolveTarget() {
|
|
437
|
+
if (this.studioClients.size === 0) return null;
|
|
438
|
+
if (this.activePlaceId !== 0) {
|
|
439
|
+
const conn = this.studioClients.get(this.activePlaceId);
|
|
440
|
+
if (conn && conn.ws.readyState === WebSocket.OPEN) return conn;
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
if (this.studioClients.size === 1) {
|
|
444
|
+
const conn = this.studioClients.values().next().value;
|
|
445
|
+
if (conn.ws.readyState === WebSocket.OPEN) return conn;
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
/** Generate an appropriate error message when no target found */
|
|
451
|
+
getTargetError() {
|
|
452
|
+
if (this.studioClients.size === 0) return "No Studio connection";
|
|
453
|
+
if (this.activePlaceId !== 0) {
|
|
454
|
+
return `Active place ${this.activePlaceId} is not connected. Use set_active_place or list_connections.`;
|
|
455
|
+
}
|
|
456
|
+
const places = [...this.studioClients.values()].map((c) => `${c.placeName ?? "Unknown"} (${c.placeId})`);
|
|
457
|
+
return `Multiple Studio instances connected: ${places.join(", ")}. Use set_active_place to choose one.`;
|
|
458
|
+
}
|
|
410
459
|
sendRequest(type, payload, timeoutMs = 1e4) {
|
|
411
460
|
return new Promise((resolve, reject) => {
|
|
412
|
-
|
|
413
|
-
|
|
461
|
+
const target = this.resolveTarget();
|
|
462
|
+
if (!target || target.ws.readyState !== WebSocket.OPEN) {
|
|
463
|
+
reject(new Error(this.getTargetError()));
|
|
414
464
|
return;
|
|
415
465
|
}
|
|
416
466
|
const msg = createMessage(type, payload);
|
|
@@ -423,31 +473,45 @@ var init_ws_server = __esm({
|
|
|
423
473
|
reject,
|
|
424
474
|
timer
|
|
425
475
|
});
|
|
426
|
-
|
|
476
|
+
target.ws.send(serializeMessage(msg));
|
|
427
477
|
});
|
|
428
478
|
}
|
|
429
479
|
sendNotification(type, payload) {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}
|
|
480
|
+
const target = this.resolveTarget();
|
|
481
|
+
if (!target || target.ws.readyState !== WebSocket.OPEN) return;
|
|
433
482
|
const msg = createMessage(type, payload);
|
|
434
|
-
|
|
483
|
+
target.ws.send(serializeMessage(msg));
|
|
435
484
|
}
|
|
436
485
|
isConnected() {
|
|
437
|
-
return this.
|
|
486
|
+
return this.resolveTarget() !== null;
|
|
438
487
|
}
|
|
439
488
|
getConnectionInfo() {
|
|
440
|
-
return this.
|
|
489
|
+
return this.resolveTarget();
|
|
490
|
+
}
|
|
491
|
+
listConnections() {
|
|
492
|
+
return [...this.studioClients.values()].filter((c) => c.ws.readyState === WebSocket.OPEN).map((c) => ({
|
|
493
|
+
placeId: c.placeId ?? 0,
|
|
494
|
+
placeName: c.placeName,
|
|
495
|
+
studioVersion: c.studioVersion,
|
|
496
|
+
connectedAt: c.connectedAt
|
|
497
|
+
}));
|
|
498
|
+
}
|
|
499
|
+
getActivePlaceId() {
|
|
500
|
+
return this.activePlaceId;
|
|
501
|
+
}
|
|
502
|
+
setActivePlaceId(placeId) {
|
|
503
|
+
this.activePlaceId = placeId;
|
|
441
504
|
}
|
|
442
505
|
getPort() {
|
|
443
506
|
return this.port;
|
|
444
507
|
}
|
|
445
508
|
stop() {
|
|
446
509
|
return new Promise((resolve) => {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
this.studioClient = null;
|
|
510
|
+
for (const conn of this.studioClients.values()) {
|
|
511
|
+
conn.ws.close();
|
|
450
512
|
}
|
|
513
|
+
this.studioClients.clear();
|
|
514
|
+
this.wsToPlaceId.clear();
|
|
451
515
|
for (const ws of this.controllers) {
|
|
452
516
|
ws.close();
|
|
453
517
|
}
|
|
@@ -494,7 +558,8 @@ var init_ws_client = __esm({
|
|
|
494
558
|
ws = null;
|
|
495
559
|
port;
|
|
496
560
|
studioConnected = false;
|
|
497
|
-
|
|
561
|
+
connections = /* @__PURE__ */ new Map();
|
|
562
|
+
activePlaceId = 0;
|
|
498
563
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
499
564
|
constructor(port = 18088) {
|
|
500
565
|
super();
|
|
@@ -538,6 +603,20 @@ var init_ws_client = __esm({
|
|
|
538
603
|
if (msg.type === "controller:welcome") {
|
|
539
604
|
const p = msg.payload;
|
|
540
605
|
this.studioConnected = p.studioConnected;
|
|
606
|
+
if (p.connections) {
|
|
607
|
+
this.connections.clear();
|
|
608
|
+
for (const c of p.connections) {
|
|
609
|
+
this.connections.set(c.placeId, {
|
|
610
|
+
connectedAt: c.connectedAt,
|
|
611
|
+
studioVersion: c.studioVersion,
|
|
612
|
+
placeId: c.placeId,
|
|
613
|
+
placeName: c.placeName
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (p.activePlaceId !== void 0) {
|
|
618
|
+
this.activePlaceId = p.activePlaceId;
|
|
619
|
+
}
|
|
541
620
|
if (this.studioConnected) {
|
|
542
621
|
this.emit("studio:connected", {});
|
|
543
622
|
}
|
|
@@ -546,19 +625,27 @@ var init_ws_client = __esm({
|
|
|
546
625
|
if (msg.type === "studio:connected") {
|
|
547
626
|
this.studioConnected = true;
|
|
548
627
|
const payload = msg.payload;
|
|
549
|
-
|
|
628
|
+
const placeId = payload.placeId ?? 0;
|
|
629
|
+
this.connections.set(placeId, {
|
|
550
630
|
connectedAt: Date.now(),
|
|
551
631
|
studioVersion: payload.studioVersion,
|
|
552
|
-
placeId
|
|
632
|
+
placeId,
|
|
553
633
|
placeName: payload.placeName
|
|
554
|
-
};
|
|
634
|
+
});
|
|
555
635
|
this.emit("studio:connected", payload);
|
|
556
636
|
return;
|
|
557
637
|
}
|
|
558
638
|
if (msg.type === "studio:disconnected") {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
this.
|
|
639
|
+
const payload = msg.payload;
|
|
640
|
+
const placeId = payload.placeId ?? 0;
|
|
641
|
+
this.connections.delete(placeId);
|
|
642
|
+
if (this.connections.size === 0) {
|
|
643
|
+
this.studioConnected = false;
|
|
644
|
+
}
|
|
645
|
+
if (this.activePlaceId === placeId) {
|
|
646
|
+
this.activePlaceId = 0;
|
|
647
|
+
}
|
|
648
|
+
this.emit("studio:disconnected", payload);
|
|
562
649
|
return;
|
|
563
650
|
}
|
|
564
651
|
if (msg.type === StudioMsg.RESPONSE) {
|
|
@@ -602,11 +689,27 @@ var init_ws_client = __esm({
|
|
|
602
689
|
this.ws.send(serializeMessage(msg));
|
|
603
690
|
}
|
|
604
691
|
isConnected() {
|
|
605
|
-
return this.studioConnected;
|
|
692
|
+
return this.studioConnected && this.connections.size > 0;
|
|
606
693
|
}
|
|
607
694
|
getConnectionInfo() {
|
|
608
|
-
if (
|
|
609
|
-
|
|
695
|
+
if (this.connections.size === 0) return null;
|
|
696
|
+
const target = this.activePlaceId !== 0 ? this.connections.get(this.activePlaceId) : this.connections.values().next().value;
|
|
697
|
+
if (!target) return null;
|
|
698
|
+
return { ...target, ws: this.ws };
|
|
699
|
+
}
|
|
700
|
+
listConnections() {
|
|
701
|
+
return [...this.connections.values()].map((c) => ({
|
|
702
|
+
placeId: c.placeId ?? 0,
|
|
703
|
+
placeName: c.placeName,
|
|
704
|
+
studioVersion: c.studioVersion,
|
|
705
|
+
connectedAt: c.connectedAt
|
|
706
|
+
}));
|
|
707
|
+
}
|
|
708
|
+
getActivePlaceId() {
|
|
709
|
+
return this.activePlaceId;
|
|
710
|
+
}
|
|
711
|
+
setActivePlaceId(placeId) {
|
|
712
|
+
this.activePlaceId = placeId;
|
|
610
713
|
}
|
|
611
714
|
getPort() {
|
|
612
715
|
return this.port;
|
|
@@ -683,6 +786,7 @@ These are built-in lessons that ship with Dominus. Follow them exactly.
|
|
|
683
786
|
- **Inspecting user's selection \u2192 \`get_selection\`, then \`get_properties\` or \`serialize_ui\`**
|
|
684
787
|
- **Reading properties \u2192 \`get_properties\` (NEVER \`run_code\` with dump scripts)**
|
|
685
788
|
- **Browsing the tree \u2192 \`get_explorer\`**
|
|
789
|
+
- **Multiple Studios open \u2192 \`list_connections\` to see all, \`set_active_place\` to target one**
|
|
686
790
|
- Anything exotic or procedural \u2192 \`run_code\` as last resort
|
|
687
791
|
|
|
688
792
|
### NEVER use run_code for:
|
|
@@ -2605,7 +2709,7 @@ async function startMcpServer() {
|
|
|
2605
2709
|
}
|
|
2606
2710
|
const mcp = new McpServer({
|
|
2607
2711
|
name: "dominus",
|
|
2608
|
-
version: "0.
|
|
2712
|
+
version: "0.6.0"
|
|
2609
2713
|
}, {
|
|
2610
2714
|
instructions: INTERNAL_MEMORY
|
|
2611
2715
|
});
|
|
@@ -3193,6 +3297,57 @@ ${" ".repeat(_depth)}}`;
|
|
|
3193
3297
|
return { content: [{ type: "text", text: code }] };
|
|
3194
3298
|
}
|
|
3195
3299
|
);
|
|
3300
|
+
mcp.tool(
|
|
3301
|
+
"list_connections",
|
|
3302
|
+
"List all Roblox Studio instances currently connected to Dominus. Shows placeId, placeName, and connection time for each. Use this when working with multiple Studio windows.",
|
|
3303
|
+
{},
|
|
3304
|
+
async () => {
|
|
3305
|
+
const connections = bridge.listConnections();
|
|
3306
|
+
const activePlaceId = bridge.getActivePlaceId();
|
|
3307
|
+
return {
|
|
3308
|
+
content: [{
|
|
3309
|
+
type: "text",
|
|
3310
|
+
text: JSON.stringify({
|
|
3311
|
+
activePlaceId: activePlaceId || "auto",
|
|
3312
|
+
connections: connections.map((c) => ({
|
|
3313
|
+
...c,
|
|
3314
|
+
active: activePlaceId === 0 && connections.length === 1 ? true : c.placeId === activePlaceId
|
|
3315
|
+
}))
|
|
3316
|
+
}, null, 2)
|
|
3317
|
+
}]
|
|
3318
|
+
};
|
|
3319
|
+
}
|
|
3320
|
+
);
|
|
3321
|
+
mcp.tool(
|
|
3322
|
+
"set_active_place",
|
|
3323
|
+
"Set which Roblox Studio instance to target when multiple are connected. Pass placeId=0 to reset to auto mode (works when only one is connected). Call list_connections first to see available placeIds.",
|
|
3324
|
+
{
|
|
3325
|
+
placeId: z.number().describe("The placeId to target. Use 0 to reset to auto-select.")
|
|
3326
|
+
},
|
|
3327
|
+
async ({ placeId }) => {
|
|
3328
|
+
const connections = bridge.listConnections();
|
|
3329
|
+
if (placeId !== 0 && !connections.some((c) => c.placeId === placeId)) {
|
|
3330
|
+
const available = connections.map((c) => `${c.placeName ?? "Unknown"} (${c.placeId})`).join(", ");
|
|
3331
|
+
return {
|
|
3332
|
+
content: [{
|
|
3333
|
+
type: "text",
|
|
3334
|
+
text: `Place ${placeId} is not connected. Available: ${available || "none"}`
|
|
3335
|
+
}]
|
|
3336
|
+
};
|
|
3337
|
+
}
|
|
3338
|
+
bridge.setActivePlaceId(placeId);
|
|
3339
|
+
if (placeId === 0) {
|
|
3340
|
+
return { content: [{ type: "text", text: "Active place reset to auto-select." }] };
|
|
3341
|
+
}
|
|
3342
|
+
const target = connections.find((c) => c.placeId === placeId);
|
|
3343
|
+
return {
|
|
3344
|
+
content: [{
|
|
3345
|
+
type: "text",
|
|
3346
|
+
text: `Active place set to ${target?.placeName ?? "Unknown"} (${placeId})`
|
|
3347
|
+
}]
|
|
3348
|
+
};
|
|
3349
|
+
}
|
|
3350
|
+
);
|
|
3196
3351
|
mcp.tool(
|
|
3197
3352
|
"recall_memory",
|
|
3198
3353
|
"Search persistent memory for facts about the current Roblox project",
|
|
@@ -3487,11 +3642,20 @@ var Setup = ({ onComplete }) => {
|
|
|
3487
3642
|
var StatusBar = React6.memo(({
|
|
3488
3643
|
connected,
|
|
3489
3644
|
placeName,
|
|
3645
|
+
connectionCount,
|
|
3490
3646
|
model,
|
|
3491
3647
|
sessionTokens
|
|
3492
3648
|
}) => {
|
|
3493
3649
|
const statusColor = connected ? "green" : "red";
|
|
3494
|
-
const
|
|
3650
|
+
const count = connectionCount ?? (connected ? 1 : 0);
|
|
3651
|
+
let statusText;
|
|
3652
|
+
if (!connected) {
|
|
3653
|
+
statusText = "\u25CB Disconnected";
|
|
3654
|
+
} else if (count > 1) {
|
|
3655
|
+
statusText = `\u25CF ${count} Studios${placeName ? ` \u2014 active: ${placeName}` : ""}`;
|
|
3656
|
+
} else {
|
|
3657
|
+
statusText = `\u25CF Connected${placeName ? ` \u2014 ${placeName}` : ""}`;
|
|
3658
|
+
}
|
|
3495
3659
|
const shortModel = model.split("/").pop() ?? model;
|
|
3496
3660
|
return /* @__PURE__ */ jsxs(
|
|
3497
3661
|
Box,
|
|
@@ -3909,6 +4073,7 @@ var ToolCallView = React6.memo(({ calls }) => {
|
|
|
3909
4073
|
var Layout = React6.memo(({
|
|
3910
4074
|
connected,
|
|
3911
4075
|
placeName,
|
|
4076
|
+
connectionCount,
|
|
3912
4077
|
model,
|
|
3913
4078
|
chatEntries,
|
|
3914
4079
|
outputEntries,
|
|
@@ -3922,7 +4087,7 @@ var Layout = React6.memo(({
|
|
|
3922
4087
|
onClearImage
|
|
3923
4088
|
}) => {
|
|
3924
4089
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "100%", children: [
|
|
3925
|
-
/* @__PURE__ */ jsx(StatusBar, { connected, placeName, model }),
|
|
4090
|
+
/* @__PURE__ */ jsx(StatusBar, { connected, placeName, connectionCount, model }),
|
|
3926
4091
|
/* @__PURE__ */ jsxs(Box, { flexGrow: 1, children: [
|
|
3927
4092
|
/* @__PURE__ */ jsx(ExplorerPane, { tree: explorerTree }),
|
|
3928
4093
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [
|
|
@@ -3948,10 +4113,12 @@ var Layout = React6.memo(({
|
|
|
3948
4113
|
init_protocol();
|
|
3949
4114
|
function useStudio(server) {
|
|
3950
4115
|
const connInfo = server.getConnectionInfo();
|
|
4116
|
+
const connections = server.listConnections();
|
|
3951
4117
|
const [state, setState] = useState({
|
|
3952
4118
|
connected: server.isConnected(),
|
|
3953
4119
|
placeName: connInfo?.placeName,
|
|
3954
4120
|
placeId: connInfo?.placeId,
|
|
4121
|
+
connectionCount: connections.length,
|
|
3955
4122
|
explorerTree: [],
|
|
3956
4123
|
outputLog: []
|
|
3957
4124
|
});
|
|
@@ -3960,27 +4127,36 @@ function useStudio(server) {
|
|
|
3960
4127
|
useEffect(() => {
|
|
3961
4128
|
if (server.isConnected() && !stateRef.current.connected) {
|
|
3962
4129
|
const info = server.getConnectionInfo();
|
|
4130
|
+
const conns = server.listConnections();
|
|
3963
4131
|
setState((prev) => ({
|
|
3964
4132
|
...prev,
|
|
3965
4133
|
connected: true,
|
|
3966
4134
|
placeName: info?.placeName,
|
|
3967
|
-
placeId: info?.placeId
|
|
4135
|
+
placeId: info?.placeId,
|
|
4136
|
+
connectionCount: conns.length
|
|
3968
4137
|
}));
|
|
3969
4138
|
}
|
|
3970
4139
|
const onConnected = (payload) => {
|
|
4140
|
+
const conns = server.listConnections();
|
|
4141
|
+
const info = server.getConnectionInfo();
|
|
3971
4142
|
setState((prev) => ({
|
|
3972
4143
|
...prev,
|
|
3973
4144
|
connected: true,
|
|
3974
|
-
placeName: payload.placeName ?? prev.placeName,
|
|
3975
|
-
placeId: payload.placeId ?? prev.placeId
|
|
4145
|
+
placeName: info?.placeName ?? payload.placeName ?? prev.placeName,
|
|
4146
|
+
placeId: info?.placeId ?? payload.placeId ?? prev.placeId,
|
|
4147
|
+
connectionCount: conns.length
|
|
3976
4148
|
}));
|
|
3977
4149
|
};
|
|
3978
4150
|
const onDisconnected = () => {
|
|
4151
|
+
const conns = server.listConnections();
|
|
4152
|
+
const info = server.getConnectionInfo();
|
|
4153
|
+
const stillConnected = conns.length > 0;
|
|
3979
4154
|
setState((prev) => ({
|
|
3980
4155
|
...prev,
|
|
3981
|
-
connected:
|
|
3982
|
-
placeName: void 0,
|
|
3983
|
-
placeId: void 0
|
|
4156
|
+
connected: stillConnected,
|
|
4157
|
+
placeName: stillConnected ? info?.placeName : void 0,
|
|
4158
|
+
placeId: stillConnected ? info?.placeId : void 0,
|
|
4159
|
+
connectionCount: conns.length
|
|
3984
4160
|
}));
|
|
3985
4161
|
};
|
|
3986
4162
|
const onExplorer = (payload) => {
|
|
@@ -4282,6 +4458,7 @@ var App = ({ server, agent: initialAgent, version }) => {
|
|
|
4282
4458
|
{
|
|
4283
4459
|
connected: studio.connected,
|
|
4284
4460
|
placeName: studio.placeName,
|
|
4461
|
+
connectionCount: studio.connectionCount,
|
|
4285
4462
|
model: agent?.getModel() ?? resolveProviderSettings(config).model,
|
|
4286
4463
|
chatEntries,
|
|
4287
4464
|
outputEntries: studio.outputLog,
|