@qodalis/react-cli 2.0.0-beta.10 → 2.0.0-beta.12

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.mjs CHANGED
@@ -203,562 +203,920 @@ function PositionIcon({ position, size = 20 }) {
203
203
  fillRect
204
204
  ] });
205
205
  }
206
- function CliPanel({ options: optionsProp, modules: modulesProp, processors: processorsProp, services: servicesProp, onClose, style, className }) {
207
- const config = useCliConfig();
208
- const options = optionsProp ?? config.options;
209
- const modules = modulesProp ?? config.modules;
210
- const processors = processorsProp ?? config.processors;
211
- const services = servicesProp ?? config.services;
212
- const [position, setPosition] = useState2(
213
- () => loadPanelPosition() ?? options?.position ?? "bottom"
214
- );
215
- const closable = options?.closable ?? true;
216
- const resizable = options?.resizable ?? true;
217
- const isHorizontal = position === "left" || position === "right";
218
- const hideable = options?.hideable ?? true;
219
- const hideAlignment = options?.hideAlignment ?? "center";
220
- const syncTheme = options?.syncTheme ?? false;
221
- const [visible, setVisible] = useState2(true);
222
- const [collapsed, setCollapsed] = useState2(options?.isCollapsed ?? true);
223
- const [maximized, setMaximized] = useState2(false);
224
- const [panelHeight, setPanelHeight] = useState2(600);
225
- const [panelWidth, setPanelWidth] = useState2(400);
226
- const [initialized, setInitialized] = useState2(false);
227
- const [hidden, setHidden] = useState2(options?.isHidden ?? false);
228
- const preHideCollapsedRef = useRef3(true);
229
- const [themeStyles, setThemeStyles] = useState2({});
230
- const wrapperRef = useRef3(null);
231
- const [tabs, setTabs] = useState2([]);
232
- const [activeTabId, setActiveTabId] = useState2(0);
233
- const [activePaneId, setActivePaneId] = useState2(0);
234
- const nextIdRef = useRef3({ tab: 1, pane: 1 });
235
- const [contextMenu, setContextMenu] = useState2({ visible: false, x: 0, y: 0, tabId: 0 });
236
- const engineMapRef = useRef3(/* @__PURE__ */ new Map());
237
- const [paneResizing, setPaneResizing] = useState2(false);
238
- const paneResizeRef = useRef3({ tabId: 0, dividerIndex: 0, startX: 0, startWidths: [], containerWidth: 0 });
239
- const [panelResizing, setPanelResizing] = useState2(false);
240
- const panelResizeRef = useRef3({ startY: 0, startHeight: 0, startX: 0, startWidth: 0 });
241
- const prevHeightRef = useRef3(600);
242
- const prevWidthRef = useRef3(400);
243
- const addTab = useCallback(() => {
244
- const paneId = nextIdRef.current.pane++;
245
- const tabId = nextIdRef.current.tab++;
246
- const pane = { id: paneId, widthPercent: 100 };
247
- const tab = { id: tabId, title: `Terminal ${tabId}`, isEditing: false, panes: [pane] };
248
- setTabs((prev) => [...prev, tab]);
249
- setActiveTabId(tabId);
250
- setActivePaneId(paneId);
251
- }, []);
252
- const toggle = useCallback(() => {
253
- setCollapsed((prev) => {
254
- const next = !prev;
255
- if (!next && !initialized) {
256
- setInitialized(true);
257
- const paneId = nextIdRef.current.pane++;
258
- const tabId = nextIdRef.current.tab++;
259
- const pane = { id: paneId, widthPercent: 100 };
260
- const tab = { id: tabId, title: `Terminal ${tabId}`, isEditing: false, panes: [pane] };
261
- setTabs([tab]);
262
- setActiveTabId(tabId);
263
- setActivePaneId(paneId);
264
- }
265
- return next;
266
- });
267
- }, [initialized]);
268
- const closeTab = useCallback((id) => {
269
- setTabs((prev) => {
270
- const tab = prev.find((t) => t.id === id);
271
- if (tab) {
272
- tab.panes.forEach((p) => engineMapRef.current.delete(p.id));
273
- }
274
- const next = prev.filter((t) => t.id !== id);
275
- if (next.length === 0) {
276
- setInitialized(false);
277
- setCollapsed(true);
278
- return [];
206
+ var CliPanel = React3.forwardRef(
207
+ function CliPanel2(props, ref) {
208
+ const { options: optionsProp, modules: modulesProp, processors: processorsProp, services: servicesProp, onClose, style, className } = props;
209
+ const config = useCliConfig();
210
+ const options = optionsProp ? { ...config.options, ...optionsProp } : config.options;
211
+ const modules = modulesProp ?? config.modules;
212
+ const processors = processorsProp ?? config.processors;
213
+ const services = servicesProp ?? config.services;
214
+ const [internalPosition, setInternalPosition] = useState2(
215
+ () => loadPanelPosition() ?? options?.position ?? "bottom"
216
+ );
217
+ const [internalCollapsed, setInternalCollapsed] = useState2(options?.isCollapsed ?? true);
218
+ const [internalHidden, setInternalHidden] = useState2(options?.isHidden ?? false);
219
+ const [internalMaximized, setInternalMaximized] = useState2(false);
220
+ const [internalHeight, setInternalHeight] = useState2(600);
221
+ const [internalWidth, setInternalWidth] = useState2(400);
222
+ const [internalActiveTabId, setInternalActiveTabId] = useState2(0);
223
+ const position = props.position !== void 0 ? props.position : internalPosition;
224
+ const collapsed = props.collapsed !== void 0 ? props.collapsed : internalCollapsed;
225
+ const hidden = props.hidden !== void 0 ? props.hidden : internalHidden;
226
+ const maximized = props.maximized !== void 0 ? props.maximized : internalMaximized;
227
+ const panelHeight = props.height !== void 0 ? props.height : internalHeight;
228
+ const panelWidth = props.width !== void 0 ? props.width : internalWidth;
229
+ const activeTabId = props.activeTabId !== void 0 ? props.activeTabId : internalActiveTabId;
230
+ const updateCollapsed = useCallback((value) => {
231
+ setInternalCollapsed(value);
232
+ props.onCollapsedChange?.(value);
233
+ }, [props.onCollapsedChange]);
234
+ const updateHidden = useCallback((value) => {
235
+ setInternalHidden(value);
236
+ props.onHiddenChange?.(value);
237
+ }, [props.onHiddenChange]);
238
+ const updateMaximized = useCallback((value) => {
239
+ setInternalMaximized(value);
240
+ props.onMaximizedChange?.(value);
241
+ }, [props.onMaximizedChange]);
242
+ const updateHeight = useCallback((value) => {
243
+ setInternalHeight(value);
244
+ props.onHeightChange?.(value);
245
+ }, [props.onHeightChange]);
246
+ const updateWidth = useCallback((value) => {
247
+ setInternalWidth(value);
248
+ props.onWidthChange?.(value);
249
+ }, [props.onWidthChange]);
250
+ const updateActiveTabId = useCallback((value) => {
251
+ setInternalActiveTabId(value);
252
+ props.onActiveTabIdChange?.(value);
253
+ }, [props.onActiveTabIdChange]);
254
+ const updatePosition = useCallback((value) => {
255
+ setInternalPosition(value);
256
+ savePanelPosition(value);
257
+ props.onPositionChange?.(value);
258
+ }, [props.onPositionChange]);
259
+ const closable = options?.closable ?? true;
260
+ const resizable = options?.resizable ?? true;
261
+ const isHorizontal = position === "left" || position === "right";
262
+ const hideable = options?.hideable ?? true;
263
+ const hideAlignment = options?.hideAlignment ?? "center";
264
+ const syncTheme = options?.syncTheme ?? false;
265
+ const [visible, setVisible] = useState2(true);
266
+ const [initialized, setInitialized] = useState2(false);
267
+ const preHideCollapsedRef = useRef3(true);
268
+ const [themeStyles, setThemeStyles] = useState2({});
269
+ const wrapperRef = useRef3(null);
270
+ const [tabs, setTabs] = useState2([]);
271
+ const [activePaneId, setActivePaneId] = useState2(0);
272
+ const nextIdRef = useRef3({ tab: 1, pane: 1 });
273
+ const [contextMenu, setContextMenu] = useState2({ visible: false, x: 0, y: 0, tabId: 0 });
274
+ const engineMapRef = useRef3(/* @__PURE__ */ new Map());
275
+ const activeTabIdRef = useRef3(activeTabId);
276
+ activeTabIdRef.current = activeTabId;
277
+ const activePaneIdRef = useRef3(activePaneId);
278
+ activePaneIdRef.current = activePaneId;
279
+ const [paneResizing, setPaneResizing] = useState2(false);
280
+ const paneResizeRef = useRef3({ tabId: 0, dividerIndex: 0, startX: 0, startWidths: [], containerWidth: 0 });
281
+ const [panelResizing, setPanelResizing] = useState2(false);
282
+ const panelResizeRef = useRef3({ startY: 0, startHeight: 0, startX: 0, startWidth: 0 });
283
+ const prevHeightRef = useRef3(600);
284
+ const prevWidthRef = useRef3(400);
285
+ const [statusExecutionState, setStatusExecutionState] = useState2("idle");
286
+ const [statusLastCommand, setStatusLastCommand] = useState2(null);
287
+ const [statusServiceCount, setStatusServiceCount] = useState2({ running: 0, total: 0 });
288
+ const [statusServiceDetails, setStatusServiceDetails] = useState2([]);
289
+ const [statusServerState, setStatusServerState] = useState2("none");
290
+ const [statusServerDetails, setStatusServerDetails] = useState2([]);
291
+ const [statusUptime, setStatusUptime] = useState2(0);
292
+ const [statusText, setStatusText] = useState2(null);
293
+ const [servicesDropdownOpen, setServicesDropdownOpen] = useState2(false);
294
+ const [serversDropdownOpen, setServersDropdownOpen] = useState2(false);
295
+ const servicesDropdownRef = useRef3(null);
296
+ const serversDropdownRef = useRef3(null);
297
+ const normalizePanes = useCallback((panes) => {
298
+ const total = panes.reduce((s, p) => s + p.widthPercent, 0);
299
+ if (total === 0) return;
300
+ const scale = 100 / total;
301
+ panes.forEach((p) => {
302
+ p.widthPercent *= scale;
303
+ });
304
+ }, []);
305
+ const addTab = useCallback((title) => {
306
+ const tabId = nextIdRef.current.tab++;
307
+ const paneId = nextIdRef.current.pane++;
308
+ const pane = { id: paneId, widthPercent: 100 };
309
+ const tab = { id: tabId, title: title ?? `Terminal ${tabId}`, isEditing: false, panes: [pane] };
310
+ setTabs((prev) => [...prev, tab]);
311
+ updateActiveTabId(tabId);
312
+ setActivePaneId(paneId);
313
+ props.onTabAdded?.({ tabId });
314
+ return tabId;
315
+ }, [updateActiveTabId, props.onTabAdded]);
316
+ const toggle = useCallback(() => {
317
+ if (collapsed) {
318
+ updateCollapsed(false);
319
+ if (!initialized) {
320
+ setInitialized(true);
321
+ addTab();
322
+ }
323
+ } else {
324
+ updateCollapsed(true);
279
325
  }
280
- setActiveTabId((current) => {
281
- if (current === id) {
326
+ }, [collapsed, initialized, updateCollapsed, addTab]);
327
+ const closeTab = useCallback((id) => {
328
+ setTabs((prev) => {
329
+ const tab = prev.find((t) => t.id === id);
330
+ if (tab) {
331
+ tab.panes.forEach((p) => {
332
+ engineMapRef.current.get(p.id)?.destroy();
333
+ engineMapRef.current.delete(p.id);
334
+ });
335
+ }
336
+ const next = prev.filter((t) => t.id !== id);
337
+ if (next.length === 0) {
338
+ setInitialized(false);
339
+ updateCollapsed(true);
340
+ return [];
341
+ }
342
+ if (activeTabIdRef.current === id) {
282
343
  const oldIdx = prev.findIndex((t) => t.id === id);
283
344
  const newIdx = Math.min(oldIdx, next.length - 1);
284
- return next[newIdx].id;
345
+ updateActiveTabId(next[newIdx].id);
285
346
  }
286
- return current;
287
- });
288
- return next;
289
- });
290
- }, []);
291
- const selectTab = useCallback((id) => {
292
- setActiveTabId(id);
293
- setTabs((prev) => {
294
- const tab = prev.find((t) => t.id === id);
295
- if (tab && tab.panes.length > 0) {
296
- setActivePaneId(tab.panes[0].id);
297
- }
298
- return prev;
299
- });
300
- }, []);
301
- const normalizePanes = (panes) => {
302
- const total = panes.reduce((s, p) => s + p.widthPercent, 0);
303
- if (total === 0) return;
304
- const scale = 100 / total;
305
- panes.forEach((p) => {
306
- p.widthPercent *= scale;
307
- });
308
- };
309
- const splitRight = useCallback((tabId, afterPaneId) => {
310
- setTabs((prev) => {
311
- const next = prev.map((t) => ({ ...t, panes: t.panes.map((p) => ({ ...p })) }));
312
- const tab = next.find((t) => t.id === (tabId ?? activeTabId));
313
- if (!tab) return prev;
314
- const targetPaneId = afterPaneId ?? activePaneId;
315
- const idx = tab.panes.findIndex((p) => p.id === targetPaneId);
316
- const insertIdx = idx === -1 ? tab.panes.length : idx + 1;
317
- const newPaneId = nextIdRef.current.pane++;
318
- const newPane = { id: newPaneId, widthPercent: 0 };
319
- tab.panes.splice(insertIdx, 0, newPane);
320
- const evenWidth = 100 / tab.panes.length;
321
- tab.panes.forEach((p) => {
322
- p.widthPercent = evenWidth;
347
+ return next;
323
348
  });
324
- normalizePanes(tab.panes);
325
- setActivePaneId(newPaneId);
326
- return next;
327
- });
328
- }, [activeTabId, activePaneId]);
329
- const closePane = useCallback((tabId, paneId) => {
330
- setTabs((prev) => {
331
- const tab = prev.find((t) => t.id === tabId);
332
- if (!tab) return prev;
333
- if (tab.panes.length <= 1) {
334
- const next2 = prev.filter((t) => t.id !== tabId);
335
- if (next2.length === 0) {
336
- setInitialized(false);
337
- setCollapsed(true);
338
- return [];
349
+ props.onTabClosed?.({ tabId: id });
350
+ }, [updateCollapsed, updateActiveTabId, props.onTabClosed]);
351
+ const selectTab = useCallback((id) => {
352
+ updateActiveTabId(id);
353
+ setTabs((prev) => {
354
+ const tab = prev.find((t) => t.id === id);
355
+ if (tab && tab.panes.length > 0) {
356
+ setActivePaneId(tab.panes[0].id);
339
357
  }
340
- return next2;
341
- }
342
- const next = prev.map((t) => ({ ...t, panes: t.panes.map((p) => ({ ...p })) }));
343
- const updatedTab = next.find((t) => t.id === tabId);
344
- const idx = updatedTab.panes.findIndex((p) => p.id === paneId);
345
- if (idx === -1) return prev;
346
- updatedTab.panes.splice(idx, 1);
347
- const totalRemaining = updatedTab.panes.reduce((s, p) => s + p.widthPercent, 0);
348
- if (totalRemaining > 0) {
349
- updatedTab.panes.forEach((p) => {
350
- p.widthPercent = p.widthPercent / totalRemaining * 100;
358
+ return prev;
359
+ });
360
+ }, [updateActiveTabId]);
361
+ const renameTab = useCallback((tabId, title) => {
362
+ setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, title } : t));
363
+ }, []);
364
+ const startRename = useCallback((tabId) => {
365
+ setTabs((prev) => prev.map((t) => ({ ...t, isEditing: t.id === tabId })));
366
+ }, []);
367
+ const commitRename = useCallback((tabId, value) => {
368
+ const trimmed = value.trim();
369
+ setTabs((prev) => prev.map(
370
+ (t) => t.id === tabId ? { ...t, title: trimmed || t.title, isEditing: false } : t
371
+ ));
372
+ }, []);
373
+ const splitPane = useCallback((tabId) => {
374
+ const targetTabId = tabId ?? activeTabIdRef.current;
375
+ const paneId = nextIdRef.current.pane++;
376
+ setTabs((prev) => prev.map((t) => {
377
+ if (t.id !== targetTabId) return t;
378
+ const newPanes = [...t.panes.map((p) => ({ ...p })), { id: paneId, widthPercent: 0 }];
379
+ const evenWidth = 100 / newPanes.length;
380
+ newPanes.forEach((p) => {
381
+ p.widthPercent = evenWidth;
351
382
  });
352
- }
353
- normalizePanes(updatedTab.panes);
354
- setActivePaneId((curr) => {
355
- if (curr === paneId) {
356
- const newIdx = Math.min(idx, updatedTab.panes.length - 1);
357
- return updatedTab.panes[newIdx].id;
383
+ normalizePanes(newPanes);
384
+ return { ...t, panes: newPanes };
385
+ }));
386
+ setActivePaneId(paneId);
387
+ props.onPaneSplit?.({ paneId, tabId: targetTabId });
388
+ return paneId;
389
+ }, [normalizePanes, props.onPaneSplit]);
390
+ const closePane = useCallback((paneId) => {
391
+ setTabs((prev) => {
392
+ for (let i = 0; i < prev.length; i++) {
393
+ const tab = prev[i];
394
+ const idx = tab.panes.findIndex((p) => p.id === paneId);
395
+ if (idx === -1) continue;
396
+ if (tab.panes.length <= 1) {
397
+ setTimeout(() => closeTab(tab.id), 0);
398
+ return prev;
399
+ }
400
+ const newPanes = tab.panes.filter((p) => p.id !== paneId);
401
+ normalizePanes(newPanes);
402
+ const newTabs = [...prev];
403
+ newTabs[i] = { ...tab, panes: newPanes };
404
+ engineMapRef.current.get(paneId)?.destroy();
405
+ engineMapRef.current.delete(paneId);
406
+ if (activePaneIdRef.current === paneId) {
407
+ setActivePaneId(newPanes[Math.min(idx, newPanes.length - 1)].id);
408
+ }
409
+ props.onPaneClosed?.({ paneId });
410
+ return newTabs;
358
411
  }
359
- return curr;
412
+ return prev;
360
413
  });
361
- return next;
362
- });
363
- }, []);
364
- const startRename = useCallback((tabId) => {
365
- setTabs((prev) => prev.map((t) => ({ ...t, isEditing: t.id === tabId })));
366
- }, []);
367
- const commitRename = useCallback((tabId, value) => {
368
- const trimmed = value.trim();
369
- setTabs((prev) => prev.map(
370
- (t) => t.id === tabId ? { ...t, title: trimmed || t.title, isEditing: false } : t
371
- ));
372
- }, []);
373
- const closeContextMenu = useCallback(() => {
374
- setContextMenu((prev) => ({ ...prev, visible: false }));
375
- }, []);
376
- useEffect3(() => {
377
- if (!contextMenu.visible) return;
378
- const handler = () => closeContextMenu();
379
- document.addEventListener("click", handler);
380
- return () => document.removeEventListener("click", handler);
381
- }, [contextMenu.visible, closeContextMenu]);
382
- const onPanelResizeStart = useCallback((e) => {
383
- if (!resizable) return;
384
- e.preventDefault();
385
- if (collapsed) {
386
- toggle();
387
- }
388
- setPanelResizing(true);
389
- panelResizeRef.current = {
390
- startY: e.clientY,
391
- startHeight: panelHeight,
392
- startX: e.clientX,
393
- startWidth: panelWidth
394
- };
395
- }, [collapsed, toggle, panelHeight, panelWidth, resizable]);
396
- useEffect3(() => {
397
- if (!panelResizing) return;
398
- const onMove = (e) => {
399
- if (isHorizontal) {
400
- const deltaX = position === "left" ? e.clientX - panelResizeRef.current.startX : panelResizeRef.current.startX - e.clientX;
401
- let next = Math.max(100, panelResizeRef.current.startWidth + deltaX);
402
- if (next > window.innerWidth) next = window.innerWidth;
403
- setPanelWidth(next);
404
- } else {
405
- const deltaY = position === "top" ? e.clientY - panelResizeRef.current.startY : panelResizeRef.current.startY - e.clientY;
406
- let next = Math.max(100, panelResizeRef.current.startHeight + deltaY);
407
- if (next > window.innerHeight) next = window.innerHeight;
408
- setPanelHeight(next);
414
+ }, [closeTab, normalizePanes, props.onPaneClosed]);
415
+ const closeContextMenu = useCallback(() => {
416
+ setContextMenu((prev) => ({ ...prev, visible: false }));
417
+ }, []);
418
+ useEffect3(() => {
419
+ if (!contextMenu.visible) return;
420
+ const handler = () => closeContextMenu();
421
+ document.addEventListener("click", handler);
422
+ return () => document.removeEventListener("click", handler);
423
+ }, [contextMenu.visible, closeContextMenu]);
424
+ const onPanelResizeStart = useCallback((e) => {
425
+ if (!resizable) return;
426
+ e.preventDefault();
427
+ if (collapsed) {
428
+ toggle();
409
429
  }
410
- };
411
- const onUp = () => setPanelResizing(false);
412
- document.addEventListener("mousemove", onMove);
413
- document.addEventListener("mouseup", onUp);
414
- return () => {
415
- document.removeEventListener("mousemove", onMove);
416
- document.removeEventListener("mouseup", onUp);
417
- };
418
- }, [panelResizing, isHorizontal, position]);
419
- const onPaneResizeStart = useCallback((e, tabId, dividerIndex) => {
420
- e.preventDefault();
421
- const tab = tabs.find((t) => t.id === tabId);
422
- if (!tab) return;
423
- setPaneResizing(true);
424
- const container = e.target.closest(".cli-panel-panes-container");
425
- paneResizeRef.current = {
426
- tabId,
427
- dividerIndex,
428
- startX: e.clientX,
429
- startWidths: tab.panes.map((p) => p.widthPercent),
430
- containerWidth: container ? container.clientWidth : 1
431
- };
432
- }, [tabs]);
433
- useEffect3(() => {
434
- if (!paneResizing) return;
435
- const onMove = (e) => {
436
- const ref = paneResizeRef.current;
437
- const deltaX = e.clientX - ref.startX;
438
- const deltaPct = deltaX / ref.containerWidth * 100;
439
- const i = ref.dividerIndex;
440
- let leftWidth = ref.startWidths[i] + deltaPct;
441
- let rightWidth = ref.startWidths[i + 1] - deltaPct;
442
- if (leftWidth < MIN_PANE_WIDTH_PERCENT) {
443
- leftWidth = MIN_PANE_WIDTH_PERCENT;
444
- rightWidth = ref.startWidths[i] + ref.startWidths[i + 1] - MIN_PANE_WIDTH_PERCENT;
445
- }
446
- if (rightWidth < MIN_PANE_WIDTH_PERCENT) {
447
- rightWidth = MIN_PANE_WIDTH_PERCENT;
448
- leftWidth = ref.startWidths[i] + ref.startWidths[i + 1] - MIN_PANE_WIDTH_PERCENT;
449
- }
450
- setTabs((prev) => {
451
- const next = prev.map((t) => ({ ...t, panes: t.panes.map((p) => ({ ...p })) }));
452
- const tab = next.find((t) => t.id === ref.tabId);
453
- if (tab) {
454
- tab.panes[i].widthPercent = leftWidth;
455
- tab.panes[i + 1].widthPercent = rightWidth;
430
+ setPanelResizing(true);
431
+ panelResizeRef.current = {
432
+ startY: e.clientY,
433
+ startHeight: panelHeight,
434
+ startX: e.clientX,
435
+ startWidth: panelWidth
436
+ };
437
+ }, [collapsed, toggle, panelHeight, panelWidth, resizable]);
438
+ useEffect3(() => {
439
+ if (!panelResizing) return;
440
+ const onMove = (e) => {
441
+ if (isHorizontal) {
442
+ const deltaX = position === "left" ? e.clientX - panelResizeRef.current.startX : panelResizeRef.current.startX - e.clientX;
443
+ let next = Math.max(100, panelResizeRef.current.startWidth + deltaX);
444
+ if (next > window.innerWidth) next = window.innerWidth;
445
+ updateWidth(next);
446
+ } else {
447
+ const deltaY = position === "top" ? e.clientY - panelResizeRef.current.startY : panelResizeRef.current.startY - e.clientY;
448
+ let next = Math.max(100, panelResizeRef.current.startHeight + deltaY);
449
+ if (next > window.innerHeight) next = window.innerHeight;
450
+ updateHeight(next);
456
451
  }
457
- return next;
458
- });
459
- };
460
- const onUp = () => {
461
- setPaneResizing(false);
462
- document.body.classList.remove("cli-pane-resizing");
463
- };
464
- document.body.classList.add("cli-pane-resizing");
465
- document.addEventListener("mousemove", onMove);
466
- document.addEventListener("mouseup", onUp);
467
- return () => {
468
- document.removeEventListener("mousemove", onMove);
469
- document.removeEventListener("mouseup", onUp);
470
- };
471
- }, [paneResizing]);
472
- useEffect3(() => {
473
- if (!syncTheme || !initialized) return;
474
- const syncFromEngine = () => {
475
- const engine = engineMapRef.current.values().next().value;
476
- if (!engine) return;
477
- const theme = engine.getTerminal().options.theme;
478
- if (theme) setThemeStyles(derivePanelThemeStyles(theme));
479
- };
480
- const timer = setTimeout(() => {
481
- syncFromEngine();
482
- const container = wrapperRef.current?.querySelector(".terminal-container");
483
- if (!container) return;
484
- const observer = new MutationObserver(syncFromEngine);
485
- observer.observe(container, { attributes: true, attributeFilter: ["style"] });
486
- return () => observer.disconnect();
487
- }, 200);
488
- return () => clearTimeout(timer);
489
- }, [syncTheme, initialized]);
490
- const toggleMaximize = useCallback(() => {
491
- setMaximized((prev) => {
492
- if (!prev) {
452
+ };
453
+ const onUp = () => setPanelResizing(false);
454
+ document.addEventListener("mousemove", onMove);
455
+ document.addEventListener("mouseup", onUp);
456
+ return () => {
457
+ document.removeEventListener("mousemove", onMove);
458
+ document.removeEventListener("mouseup", onUp);
459
+ };
460
+ }, [panelResizing, isHorizontal, position, updateWidth, updateHeight]);
461
+ const onPaneResizeStart = useCallback((e, tabId, dividerIndex) => {
462
+ e.preventDefault();
463
+ const tab = tabs.find((t) => t.id === tabId);
464
+ if (!tab) return;
465
+ setPaneResizing(true);
466
+ const container = e.target.closest(".cli-panel-panes-container");
467
+ paneResizeRef.current = {
468
+ tabId,
469
+ dividerIndex,
470
+ startX: e.clientX,
471
+ startWidths: tab.panes.map((p) => p.widthPercent),
472
+ containerWidth: container ? container.clientWidth : 1
473
+ };
474
+ }, [tabs]);
475
+ useEffect3(() => {
476
+ if (!paneResizing) return;
477
+ const onMove = (e) => {
478
+ const ref2 = paneResizeRef.current;
479
+ const deltaX = e.clientX - ref2.startX;
480
+ const deltaPct = deltaX / ref2.containerWidth * 100;
481
+ const i = ref2.dividerIndex;
482
+ let leftWidth = ref2.startWidths[i] + deltaPct;
483
+ let rightWidth = ref2.startWidths[i + 1] - deltaPct;
484
+ if (leftWidth < MIN_PANE_WIDTH_PERCENT) {
485
+ leftWidth = MIN_PANE_WIDTH_PERCENT;
486
+ rightWidth = ref2.startWidths[i] + ref2.startWidths[i + 1] - MIN_PANE_WIDTH_PERCENT;
487
+ }
488
+ if (rightWidth < MIN_PANE_WIDTH_PERCENT) {
489
+ rightWidth = MIN_PANE_WIDTH_PERCENT;
490
+ leftWidth = ref2.startWidths[i] + ref2.startWidths[i + 1] - MIN_PANE_WIDTH_PERCENT;
491
+ }
492
+ setTabs((prev) => {
493
+ const next = prev.map((t) => ({ ...t, panes: t.panes.map((p) => ({ ...p })) }));
494
+ const tab = next.find((t) => t.id === ref2.tabId);
495
+ if (tab) {
496
+ tab.panes[i].widthPercent = leftWidth;
497
+ tab.panes[i + 1].widthPercent = rightWidth;
498
+ }
499
+ return next;
500
+ });
501
+ };
502
+ const onUp = () => {
503
+ setPaneResizing(false);
504
+ document.body.classList.remove("cli-pane-resizing");
505
+ };
506
+ document.body.classList.add("cli-pane-resizing");
507
+ document.addEventListener("mousemove", onMove);
508
+ document.addEventListener("mouseup", onUp);
509
+ return () => {
510
+ document.removeEventListener("mousemove", onMove);
511
+ document.removeEventListener("mouseup", onUp);
512
+ };
513
+ }, [paneResizing]);
514
+ useEffect3(() => {
515
+ if (!syncTheme || !initialized) return;
516
+ const syncFromEngine = () => {
517
+ const engine = engineMapRef.current.values().next().value;
518
+ if (!engine) return;
519
+ const theme = engine.getTerminal().options.theme;
520
+ if (theme) setThemeStyles(derivePanelThemeStyles(theme));
521
+ };
522
+ const timer = setTimeout(() => {
523
+ syncFromEngine();
524
+ const container = wrapperRef.current?.querySelector(".terminal-container");
525
+ if (!container) return;
526
+ const observer = new MutationObserver(syncFromEngine);
527
+ observer.observe(container, { attributes: true, attributeFilter: ["style"] });
528
+ return () => observer.disconnect();
529
+ }, 200);
530
+ return () => clearTimeout(timer);
531
+ }, [syncTheme, initialized]);
532
+ useEffect3(() => {
533
+ if (!initialized) return;
534
+ const pollExec = setInterval(() => {
535
+ const tab = tabs.find((t) => t.id === activeTabIdRef.current);
536
+ if (!tab) return;
537
+ const engine = engineMapRef.current.get(tab.panes[0]?.id);
538
+ if (!engine) return;
539
+ const context = engine.getContext();
540
+ if (!context) return;
541
+ const running = !!context.isExecuting || !!context.contextProcessor;
542
+ setStatusExecutionState(running ? "running" : "idle");
543
+ const result = context.lastCommandResult;
544
+ setStatusLastCommand(result ? { name: result.command, success: result.success } : null);
545
+ const text = context.getStatusText?.();
546
+ setStatusText(text || null);
547
+ }, 300);
548
+ const pollGlobal = setInterval(() => {
549
+ const tab = tabs.find((t) => t.id === activeTabIdRef.current);
550
+ if (!tab) return;
551
+ const engine = engineMapRef.current.get(tab.panes[0]?.id);
552
+ if (!engine) return;
553
+ const context = engine.getContext();
554
+ if (!context) return;
555
+ try {
556
+ const services2 = context.backgroundServices?.list() ?? [];
557
+ setStatusServiceCount({ running: services2.filter((s) => s.status === "running").length, total: services2.length });
558
+ setStatusServiceDetails(services2.map((s) => ({ name: s.name, status: s.status, description: s.description })));
559
+ } catch {
560
+ }
561
+ try {
562
+ let serverManager;
563
+ try {
564
+ serverManager = context.services?.get?.("cli-server-manager");
565
+ } catch {
566
+ }
567
+ const details = [];
568
+ if (serverManager?.connections?.size > 0) {
569
+ let anyConnected = false;
570
+ for (const [name, conn] of serverManager.connections) {
571
+ if (conn.connected) anyConnected = true;
572
+ details.push({
573
+ name,
574
+ url: conn.config?.url ?? "",
575
+ connected: !!conn.connected,
576
+ apiVersion: conn.connected ? conn.apiVersion : void 0,
577
+ commandCount: conn.connected ? conn.commands?.length : void 0
578
+ });
579
+ }
580
+ setStatusServerState(anyConnected ? "connected" : "disconnected");
581
+ } else {
582
+ const configuredServers = engine.options?.servers;
583
+ if (Array.isArray(configuredServers) && configuredServers.length > 0) {
584
+ for (const srv of configuredServers) {
585
+ if (srv.enabled === false) continue;
586
+ details.push({
587
+ name: srv.name,
588
+ url: srv.url ?? "",
589
+ connected: false
590
+ });
591
+ }
592
+ setStatusServerState("disconnected");
593
+ } else {
594
+ setStatusServerState("none");
595
+ }
596
+ }
597
+ setStatusServerDetails(details);
598
+ } catch {
599
+ }
600
+ setStatusUptime(engine.startedAt ? Date.now() - engine.startedAt : 0);
601
+ }, 2e3);
602
+ return () => {
603
+ clearInterval(pollExec);
604
+ clearInterval(pollGlobal);
605
+ };
606
+ }, [initialized, tabs]);
607
+ const toggleMaximize = useCallback(() => {
608
+ const nextMaximized = !maximized;
609
+ if (nextMaximized) {
493
610
  if (isHorizontal) {
494
611
  prevWidthRef.current = panelWidth;
495
- setPanelWidth(window.innerWidth);
612
+ updateWidth(window.innerWidth);
496
613
  } else {
497
614
  prevHeightRef.current = panelHeight;
498
- setPanelHeight(window.innerHeight);
615
+ updateHeight(window.innerHeight);
499
616
  }
500
617
  } else {
501
618
  if (isHorizontal) {
502
- setPanelWidth(prevWidthRef.current);
619
+ updateWidth(prevWidthRef.current);
503
620
  } else {
504
- setPanelHeight(prevHeightRef.current);
621
+ updateHeight(prevHeightRef.current);
505
622
  }
506
623
  }
507
- return !prev;
508
- });
509
- }, [panelHeight, panelWidth, isHorizontal]);
510
- const handleClose = useCallback(() => {
511
- setVisible(false);
512
- onClose?.();
513
- }, [onClose]);
514
- const handleHide = useCallback(() => {
515
- preHideCollapsedRef.current = collapsed;
516
- setHidden(true);
517
- }, [collapsed]);
518
- const handleUnhide = useCallback(() => {
519
- setHidden(false);
520
- setCollapsed(preHideCollapsedRef.current);
521
- }, []);
522
- const [positionDropdownOpen, setPositionDropdownOpen] = useState2(false);
523
- const closePositionDropdown = useCallback(() => setPositionDropdownOpen(false), []);
524
- useEffect3(() => {
525
- if (!positionDropdownOpen) return;
526
- document.addEventListener("click", closePositionDropdown);
527
- return () => document.removeEventListener("click", closePositionDropdown);
528
- }, [positionDropdownOpen, closePositionDropdown]);
529
- const handlePositionButtonClick = useCallback((e) => {
530
- e.stopPropagation();
531
- setPositionDropdownOpen((prev) => !prev);
532
- }, []);
533
- const selectPosition = useCallback((pos) => {
534
- setPositionDropdownOpen(false);
535
- setPosition(pos);
536
- savePanelPosition(pos);
537
- }, []);
538
- if (!visible) return null;
539
- const wrapperStyle = {
540
- ...isHorizontal ? { width: `${panelWidth}px` } : { height: `${panelHeight}px` },
541
- ...hidden ? { display: "none" } : {},
542
- ...themeStyles,
543
- ...style
544
- };
545
- return /* @__PURE__ */ jsxs(Fragment2, { children: [
546
- hidden && /* @__PURE__ */ jsxs(
547
- "button",
548
- {
549
- className: "cli-panel-hide-tab",
550
- "data-position": position,
551
- "data-hide-align": hideAlignment,
552
- style: themeStyles,
553
- title: "Show CLI",
554
- onClick: handleUnhide,
555
- children: [
556
- /* @__PURE__ */ jsxs("svg", { className: "cli-panel-hide-tab-icon", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
557
- /* @__PURE__ */ jsx3("polyline", { points: "4 17 10 11 4 5" }),
558
- /* @__PURE__ */ jsx3("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
559
- ] }),
560
- /* @__PURE__ */ jsx3("span", { className: "cli-panel-hide-tab-label", children: "CLI" }),
561
- /* @__PURE__ */ jsx3(HideTabChevron, { position })
562
- ]
563
- }
564
- ),
565
- /* @__PURE__ */ jsxs(
566
- "div",
567
- {
568
- ref: wrapperRef,
569
- className: `cli-panel-wrapper ${collapsed ? "collapsed" : ""} ${maximized ? "maximized" : ""} ${panelResizing ? "resizing" : ""} ${className ?? ""}`,
570
- style: wrapperStyle,
571
- "data-position": position,
572
- "data-resizable": String(resizable),
573
- "data-closable": String(closable),
574
- "data-hideable": String(hideable),
575
- children: [
576
- /* @__PURE__ */ jsxs("div", { className: "cli-panel-header", children: [
577
- /* @__PURE__ */ jsx3("div", { className: "cli-panel-resize-bar", onMouseDown: onPanelResizeStart, children: /* @__PURE__ */ jsx3("div", { className: "cli-panel-resize-grip" }) }),
578
- /* @__PURE__ */ jsxs("div", { className: "cli-panel-header-content", children: [
579
- /* @__PURE__ */ jsxs("p", { className: "cli-panel-title", children: [
580
- /* @__PURE__ */ jsx3("span", { className: "cli-panel-title-icon", children: /* @__PURE__ */ jsx3(TerminalIcon, {}) }),
581
- "CLI"
582
- ] }),
583
- /* @__PURE__ */ jsxs("div", { className: "cli-panel-action-buttons", children: [
584
- /* @__PURE__ */ jsxs("div", { className: "cli-panel-btn-position-wrapper", onClick: (e) => e.stopPropagation(), children: [
585
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn cli-panel-btn-position", title: "Move panel", onClick: handlePositionButtonClick, children: /* @__PURE__ */ jsx3(PositionIcon, { position }) }),
586
- positionDropdownOpen && /* @__PURE__ */ jsx3("div", { className: "cli-panel-position-dropdown", children: ["bottom", "top", "left", "right"].map((pos) => /* @__PURE__ */ jsxs(
587
- "button",
624
+ updateMaximized(nextMaximized);
625
+ }, [maximized, panelHeight, panelWidth, isHorizontal, updateMaximized, updateWidth, updateHeight]);
626
+ const handleClose = useCallback(() => {
627
+ setVisible(false);
628
+ onClose?.();
629
+ }, [onClose]);
630
+ const handleHide = useCallback(() => {
631
+ preHideCollapsedRef.current = collapsed;
632
+ updateHidden(true);
633
+ }, [collapsed, updateHidden]);
634
+ const handleUnhide = useCallback(() => {
635
+ updateHidden(false);
636
+ updateCollapsed(preHideCollapsedRef.current);
637
+ }, [updateHidden, updateCollapsed]);
638
+ const [positionDropdownOpen, setPositionDropdownOpen] = useState2(false);
639
+ const closePositionDropdown = useCallback(() => setPositionDropdownOpen(false), []);
640
+ useEffect3(() => {
641
+ if (!positionDropdownOpen) return;
642
+ document.addEventListener("click", closePositionDropdown);
643
+ return () => document.removeEventListener("click", closePositionDropdown);
644
+ }, [positionDropdownOpen, closePositionDropdown]);
645
+ useEffect3(() => {
646
+ if (!servicesDropdownOpen && !serversDropdownOpen) return;
647
+ const handler = () => {
648
+ setServicesDropdownOpen(false);
649
+ setServersDropdownOpen(false);
650
+ };
651
+ document.addEventListener("click", handler);
652
+ return () => document.removeEventListener("click", handler);
653
+ }, [servicesDropdownOpen, serversDropdownOpen]);
654
+ const handlePositionButtonClick = useCallback((e) => {
655
+ e.stopPropagation();
656
+ setPositionDropdownOpen((prev) => !prev);
657
+ }, []);
658
+ const selectPosition = useCallback((pos) => {
659
+ setPositionDropdownOpen(false);
660
+ updatePosition(pos);
661
+ }, [updatePosition]);
662
+ const getEngine = useCallback((paneId) => {
663
+ const targetId = paneId ?? activePaneIdRef.current;
664
+ return engineMapRef.current.get(targetId);
665
+ }, []);
666
+ const getState = useCallback(() => ({
667
+ collapsed,
668
+ hidden,
669
+ maximized,
670
+ position,
671
+ height: panelHeight,
672
+ width: panelWidth,
673
+ activeTabId,
674
+ activePaneId,
675
+ tabs: tabs.map((t) => ({
676
+ id: t.id,
677
+ title: t.title,
678
+ panes: t.panes.map((p) => ({ id: p.id, widthPercent: p.widthPercent }))
679
+ }))
680
+ }), [collapsed, hidden, maximized, position, panelHeight, panelWidth, activeTabId, activePaneId, tabs]);
681
+ React3.useImperativeHandle(ref, () => ({
682
+ open: () => {
683
+ if (!visible) {
684
+ setVisible(true);
685
+ }
686
+ if (hidden) {
687
+ updateHidden(false);
688
+ }
689
+ if (collapsed) {
690
+ updateCollapsed(false);
691
+ if (!initialized) {
692
+ setInitialized(true);
693
+ addTab();
694
+ }
695
+ }
696
+ },
697
+ collapse: () => {
698
+ if (!collapsed) updateCollapsed(true);
699
+ },
700
+ toggleCollapse: () => {
701
+ if (collapsed) {
702
+ updateCollapsed(false);
703
+ if (!initialized) {
704
+ setInitialized(true);
705
+ addTab();
706
+ }
707
+ } else {
708
+ updateCollapsed(true);
709
+ }
710
+ },
711
+ hide: () => {
712
+ if (!hidden) updateHidden(true);
713
+ },
714
+ unhide: () => {
715
+ if (hidden) updateHidden(false);
716
+ },
717
+ toggleHide: () => {
718
+ updateHidden(!hidden);
719
+ },
720
+ close: handleClose,
721
+ maximize: () => {
722
+ if (!maximized) updateMaximized(true);
723
+ },
724
+ restore: () => {
725
+ if (maximized) updateMaximized(false);
726
+ },
727
+ toggleMaximize: () => {
728
+ updateMaximized(!maximized);
729
+ },
730
+ resize: (dims) => {
731
+ if (dims.height !== void 0) updateHeight(dims.height);
732
+ if (dims.width !== void 0) updateWidth(dims.width);
733
+ },
734
+ setPosition: updatePosition,
735
+ addTab,
736
+ closeTab,
737
+ selectTab,
738
+ renameTab,
739
+ splitPane,
740
+ closePane,
741
+ getEngine,
742
+ getState
743
+ }), [
744
+ collapsed,
745
+ hidden,
746
+ maximized,
747
+ initialized,
748
+ updateCollapsed,
749
+ updateHidden,
750
+ updateMaximized,
751
+ updateHeight,
752
+ updateWidth,
753
+ updatePosition,
754
+ handleClose,
755
+ addTab,
756
+ closeTab,
757
+ selectTab,
758
+ renameTab,
759
+ splitPane,
760
+ closePane,
761
+ getEngine,
762
+ getState
763
+ ]);
764
+ const formattedUptime = (() => {
765
+ const mins = Math.floor(statusUptime / 6e4);
766
+ if (mins < 60) return `${mins}m`;
767
+ const hrs = Math.floor(mins / 60);
768
+ return `${hrs}h${mins % 60}m`;
769
+ })();
770
+ if (!visible) return null;
771
+ const wrapperStyle = {
772
+ ...isHorizontal ? { width: `${panelWidth}px` } : { height: `${panelHeight}px` },
773
+ ...hidden ? { display: "none" } : {},
774
+ ...themeStyles,
775
+ ...style
776
+ };
777
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
778
+ hidden && /* @__PURE__ */ jsxs(
779
+ "button",
780
+ {
781
+ className: "cli-panel-hide-tab",
782
+ "data-position": position,
783
+ "data-hide-align": hideAlignment,
784
+ style: themeStyles,
785
+ title: "Show CLI",
786
+ onClick: handleUnhide,
787
+ children: [
788
+ /* @__PURE__ */ jsxs("svg", { className: "cli-panel-hide-tab-icon", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
789
+ /* @__PURE__ */ jsx3("polyline", { points: "4 17 10 11 4 5" }),
790
+ /* @__PURE__ */ jsx3("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
791
+ ] }),
792
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-hide-tab-label", children: "CLI" }),
793
+ /* @__PURE__ */ jsx3(HideTabChevron, { position })
794
+ ]
795
+ }
796
+ ),
797
+ /* @__PURE__ */ jsxs(
798
+ "div",
799
+ {
800
+ ref: wrapperRef,
801
+ className: `cli-panel-wrapper ${collapsed ? "collapsed" : ""} ${maximized ? "maximized" : ""} ${panelResizing ? "resizing" : ""} ${className ?? ""}`,
802
+ style: wrapperStyle,
803
+ "data-position": position,
804
+ "data-resizable": String(resizable),
805
+ "data-closable": String(closable),
806
+ "data-hideable": String(hideable),
807
+ children: [
808
+ /* @__PURE__ */ jsxs("div", { className: "cli-panel-header", children: [
809
+ /* @__PURE__ */ jsx3("div", { className: "cli-panel-resize-bar", onMouseDown: onPanelResizeStart, children: /* @__PURE__ */ jsx3("div", { className: "cli-panel-resize-grip" }) }),
810
+ /* @__PURE__ */ jsxs("div", { className: "cli-panel-header-content", children: [
811
+ /* @__PURE__ */ jsxs("p", { className: "cli-panel-title", children: [
812
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-title-icon", children: /* @__PURE__ */ jsx3(TerminalIcon, {}) }),
813
+ "CLI"
814
+ ] }),
815
+ (position === "bottom" || position === "top") && /* @__PURE__ */ jsxs("div", { className: "cli-panel-status-indicators", children: [
816
+ /* @__PURE__ */ jsxs("span", { className: `cli-panel-status-item${statusExecutionState === "running" ? " status-running" : ""}`, children: [
817
+ /* @__PURE__ */ jsx3("span", { className: `cli-panel-status-dot ${statusExecutionState === "running" ? "dot-running" : "dot-idle"}` }),
818
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-status-label", children: statusExecutionState })
819
+ ] }),
820
+ statusServiceCount.total > 0 && /* @__PURE__ */ jsxs(
821
+ "span",
588
822
  {
589
- className: `cli-panel-position-dropdown-item${position === pos ? " active" : ""}`,
590
- onClick: () => selectPosition(pos),
823
+ ref: servicesDropdownRef,
824
+ className: "cli-panel-status-item status-clickable",
825
+ onClick: (e) => {
826
+ e.stopPropagation();
827
+ setServicesDropdownOpen((prev) => !prev);
828
+ setServersDropdownOpen(false);
829
+ },
591
830
  children: [
592
- /* @__PURE__ */ jsx3(PositionIcon, { position: pos, size: 16 }),
593
- pos.charAt(0).toUpperCase() + pos.slice(1)
831
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-status-icon", children: "\u2699" }),
832
+ /* @__PURE__ */ jsxs("span", { className: "cli-panel-status-label", children: [
833
+ statusServiceCount.running,
834
+ "/",
835
+ statusServiceCount.total,
836
+ " services"
837
+ ] })
594
838
  ]
595
- },
596
- pos
597
- )) })
598
- ] }),
599
- hideable && /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn cli-panel-btn-hide", title: "Hide", onClick: handleHide, children: /* @__PURE__ */ jsx3(HideIcon, {}) }),
600
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn", title: maximized ? "Restore" : "Maximize", disabled: collapsed, onClick: toggleMaximize, children: maximized ? /* @__PURE__ */ jsx3(RestoreIcon, {}) : /* @__PURE__ */ jsx3(MaximizeIcon, {}) }),
601
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn", title: collapsed ? "Expand" : "Collapse", onClick: toggle, children: /* @__PURE__ */ jsx3(CollapseChevron, { position, isCollapsed: collapsed }) }),
602
- closable && /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn cli-panel-btn-close", title: "Close", onClick: handleClose, children: /* @__PURE__ */ jsx3(CloseIcon, {}) })
603
- ] })
604
- ] })
605
- ] }),
606
- initialized && /* @__PURE__ */ jsxs("div", { className: "cli-panel-content", style: collapsed ? { display: "none" } : void 0, children: [
607
- /* @__PURE__ */ jsxs("div", { className: "cli-panel-tabs", children: [
608
- /* @__PURE__ */ jsx3("ul", { className: "cli-panel-tab-list", children: tabs.map((tab) => /* @__PURE__ */ jsx3(
609
- "li",
610
- {
611
- className: `cli-panel-tab ${tab.id === activeTabId ? "active" : ""}`,
612
- onClick: () => selectTab(tab.id),
613
- onDoubleClick: () => startRename(tab.id),
614
- onContextMenu: (e) => {
615
- e.preventDefault();
616
- e.stopPropagation();
617
- setContextMenu({ visible: true, x: e.clientX, y: e.clientY, tabId: tab.id });
618
- },
619
- children: tab.isEditing ? /* @__PURE__ */ jsx3(
620
- "input",
839
+ }
840
+ ),
841
+ statusLastCommand && /* @__PURE__ */ jsxs("span", { className: "cli-panel-status-item", children: [
842
+ /* @__PURE__ */ jsx3("span", { className: `cli-panel-status-icon ${statusLastCommand.success ? "status-success" : "status-error"}`, children: statusLastCommand.success ? "\u2713" : "\u2717" }),
843
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-status-label", children: statusLastCommand.name })
844
+ ] }),
845
+ statusServerState !== "none" && /* @__PURE__ */ jsxs(
846
+ "span",
621
847
  {
622
- className: "cli-panel-tab-rename-input",
623
- type: "text",
624
- defaultValue: tab.title,
625
- autoFocus: true,
626
- onKeyDown: (e) => {
627
- if (e.key === "Enter") commitRename(tab.id, e.target.value);
628
- else if (e.key === "Escape") setTabs((prev) => prev.map((t) => ({ ...t, isEditing: false })));
848
+ ref: serversDropdownRef,
849
+ className: "cli-panel-status-item status-clickable",
850
+ onClick: (e) => {
851
+ e.stopPropagation();
852
+ setServersDropdownOpen((prev) => !prev);
853
+ setServicesDropdownOpen(false);
629
854
  },
630
- onBlur: (e) => commitRename(tab.id, e.target.value),
631
- onClick: (e) => e.stopPropagation(),
632
- onDoubleClick: (e) => e.stopPropagation()
855
+ children: [
856
+ /* @__PURE__ */ jsx3("span", { className: `cli-panel-status-dot ${statusServerState === "connected" ? "dot-idle" : "dot-error"}` }),
857
+ /* @__PURE__ */ jsxs("span", { className: "cli-panel-status-label", children: [
858
+ statusServerDetails.filter((s) => s.connected).length,
859
+ "/",
860
+ statusServerDetails.length,
861
+ " servers"
862
+ ] })
863
+ ]
633
864
  }
634
- ) : /* @__PURE__ */ jsxs(Fragment2, { children: [
635
- /* @__PURE__ */ jsx3("span", { className: "cli-panel-tab-title", children: tab.title }),
636
- /* @__PURE__ */ jsx3(
865
+ ),
866
+ statusUptime > 0 && /* @__PURE__ */ jsxs("span", { className: "cli-panel-status-item status-muted", children: [
867
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-status-icon", children: "\u2191" }),
868
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-status-label", children: formattedUptime })
869
+ ] }),
870
+ statusText && /* @__PURE__ */ jsx3("span", { className: "cli-panel-status-item status-text", children: /* @__PURE__ */ jsx3("span", { className: "cli-panel-status-label", children: statusText }) })
871
+ ] }),
872
+ /* @__PURE__ */ jsxs("div", { className: "cli-panel-action-buttons", children: [
873
+ /* @__PURE__ */ jsxs("div", { className: "cli-panel-btn-position-wrapper", onClick: (e) => e.stopPropagation(), children: [
874
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn cli-panel-btn-position", title: "Move panel", onClick: handlePositionButtonClick, children: /* @__PURE__ */ jsx3(PositionIcon, { position }) }),
875
+ positionDropdownOpen && /* @__PURE__ */ jsx3("div", { className: "cli-panel-position-dropdown", children: ["bottom", "top", "left", "right"].map((pos) => /* @__PURE__ */ jsxs(
637
876
  "button",
638
877
  {
639
- className: "cli-panel-tab-close-btn",
640
- title: "Close tab",
641
- onClick: (e) => {
642
- e.stopPropagation();
643
- closeTab(tab.id);
644
- },
645
- children: "\xD7"
646
- }
647
- )
648
- ] })
649
- },
650
- tab.id
651
- )) }),
652
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-add-tab", title: "New terminal", onClick: addTab, children: "+" })
878
+ className: `cli-panel-position-dropdown-item${position === pos ? " active" : ""}`,
879
+ onClick: () => selectPosition(pos),
880
+ children: [
881
+ /* @__PURE__ */ jsx3(PositionIcon, { position: pos, size: 16 }),
882
+ pos.charAt(0).toUpperCase() + pos.slice(1)
883
+ ]
884
+ },
885
+ pos
886
+ )) })
887
+ ] }),
888
+ hideable && /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn cli-panel-btn-hide", title: "Hide", onClick: handleHide, children: /* @__PURE__ */ jsx3(HideIcon, {}) }),
889
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn", title: maximized ? "Restore" : "Maximize", disabled: collapsed, onClick: toggleMaximize, children: maximized ? /* @__PURE__ */ jsx3(RestoreIcon, {}) : /* @__PURE__ */ jsx3(MaximizeIcon, {}) }),
890
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn", title: collapsed ? "Expand" : "Collapse", onClick: toggle, children: /* @__PURE__ */ jsx3(CollapseChevron, { position, isCollapsed: collapsed }) }),
891
+ closable && /* @__PURE__ */ jsx3("button", { className: "cli-panel-btn cli-panel-btn-close", title: "Close", onClick: handleClose, children: /* @__PURE__ */ jsx3(CloseIcon, {}) })
892
+ ] })
893
+ ] }),
894
+ /* @__PURE__ */ jsx3("div", { className: `cli-panel-glow-line${statusExecutionState === "running" ? " glow-active" : ""}` })
653
895
  ] }),
654
- /* @__PURE__ */ jsx3("div", { className: "cli-panel-instances", children: tabs.map((tab) => /* @__PURE__ */ jsx3("div", { className: "cli-panel-instance", style: { display: tab.id === activeTabId ? void 0 : "none" }, children: /* @__PURE__ */ jsx3("div", { className: `cli-panel-panes-container ${paneResizing ? "resizing" : ""}`, children: tab.panes.map((pane, i) => /* @__PURE__ */ jsxs(React3.Fragment, { children: [
655
- i > 0 && /* @__PURE__ */ jsx3("div", { className: "cli-panel-pane-divider", onMouseDown: (e) => onPaneResizeStart(e, tab.id, i - 1), children: /* @__PURE__ */ jsx3("div", { className: "cli-panel-pane-divider-grip" }) }),
656
- /* @__PURE__ */ jsxs(
657
- "div",
658
- {
659
- className: `cli-panel-pane ${pane.id === activePaneId && tab.id === activeTabId ? "active-pane" : ""}`,
660
- style: { flex: `${pane.widthPercent} 1 0` },
661
- onClick: () => {
662
- setActivePaneId(pane.id);
663
- setActiveTabId(tab.id);
664
- },
665
- children: [
666
- tab.panes.length > 1 && /* @__PURE__ */ jsx3(
667
- "button",
896
+ initialized && /* @__PURE__ */ jsxs("div", { className: "cli-panel-content", style: collapsed ? { display: "none" } : void 0, children: [
897
+ /* @__PURE__ */ jsxs("div", { className: "cli-panel-tabs", children: [
898
+ /* @__PURE__ */ jsx3("ul", { className: "cli-panel-tab-list", children: tabs.map((tab) => /* @__PURE__ */ jsx3(
899
+ "li",
900
+ {
901
+ className: `cli-panel-tab ${tab.id === activeTabId ? "active" : ""}`,
902
+ onClick: () => selectTab(tab.id),
903
+ onDoubleClick: () => startRename(tab.id),
904
+ onContextMenu: (e) => {
905
+ e.preventDefault();
906
+ e.stopPropagation();
907
+ setContextMenu({ visible: true, x: e.clientX, y: e.clientY, tabId: tab.id });
908
+ },
909
+ children: tab.isEditing ? /* @__PURE__ */ jsx3(
910
+ "input",
668
911
  {
669
- className: "cli-panel-pane-close-btn",
670
- onClick: (e) => {
671
- e.stopPropagation();
672
- closePane(tab.id, pane.id);
912
+ className: "cli-panel-tab-rename-input",
913
+ type: "text",
914
+ defaultValue: tab.title,
915
+ autoFocus: true,
916
+ onKeyDown: (e) => {
917
+ if (e.key === "Enter") commitRename(tab.id, e.target.value);
918
+ else if (e.key === "Escape") setTabs((prev) => prev.map((t) => ({ ...t, isEditing: false })));
673
919
  },
674
- title: "Close pane",
675
- children: "\xD7"
920
+ onBlur: (e) => commitRename(tab.id, e.target.value),
921
+ onClick: (e) => e.stopPropagation(),
922
+ onDoubleClick: (e) => e.stopPropagation()
676
923
  }
677
- ),
678
- /* @__PURE__ */ jsx3(CliContext.Provider, { value: { engine: null }, children: /* @__PURE__ */ jsx3(
679
- Cli,
680
- {
681
- options,
682
- modules,
683
- processors,
684
- services,
685
- snapshot: pane.snapshot,
686
- onReady: (engine) => engineMapRef.current.set(pane.id, engine)
687
- }
688
- ) })
689
- ]
690
- }
691
- )
692
- ] }, pane.id)) }) }, tab.id)) })
693
- ] })
694
- ]
695
- }
696
- ),
697
- contextMenu.visible && /* @__PURE__ */ jsxs(
698
- "div",
699
- {
700
- className: "cli-panel-context-menu",
701
- style: { left: contextMenu.x, top: contextMenu.y },
702
- onClick: (e) => e.stopPropagation(),
703
- children: [
704
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
705
- closeContextMenu();
706
- startRename(contextMenu.tabId);
707
- }, children: "Rename" }),
708
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
709
- closeContextMenu();
710
- const tab = tabs.find((t) => t.id === contextMenu.tabId);
711
- if (!tab) return;
712
- const sourceEngine = engineMapRef.current.get(tab.panes[0]?.id);
713
- const snapshot = sourceEngine?.snapshot();
714
- const paneId = nextIdRef.current.pane++;
715
- const tabId = nextIdRef.current.tab++;
716
- const pane = { id: paneId, widthPercent: 100, snapshot };
717
- const newTab = { id: tabId, title: `${tab.title} (copy)`, isEditing: false, panes: [pane] };
718
- const idx = tabs.indexOf(tab);
719
- setTabs((prev) => {
720
- const next = [...prev];
721
- next.splice(idx + 1, 0, newTab);
722
- return next;
723
- });
724
- setActiveTabId(tabId);
725
- setActivePaneId(paneId);
726
- }, children: "Duplicate" }),
727
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
728
- closeContextMenu();
729
- splitRight(contextMenu.tabId);
730
- }, children: "Split Right" }),
731
- /* @__PURE__ */ jsx3("div", { className: "cli-panel-context-menu-separator" }),
732
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
733
- closeContextMenu();
734
- closeTab(contextMenu.tabId);
735
- }, children: "Close" }),
736
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", disabled: tabs.length <= 1, onClick: () => {
737
- closeContextMenu();
738
- setTabs((prev) => prev.filter((t) => t.id === contextMenu.tabId));
739
- setActiveTabId(contextMenu.tabId);
740
- }, children: "Close Others" }),
741
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
742
- const id = contextMenu.tabId;
743
- closeContextMenu();
744
- setTabs((prev) => {
745
- const idx = prev.findIndex((t) => t.id === id);
746
- if (idx === -1) return prev;
747
- return prev.slice(0, idx + 1);
748
- });
749
- }, children: "Close to the Right" }),
750
- /* @__PURE__ */ jsx3("div", { className: "cli-panel-context-menu-separator" }),
751
- /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item destructive", onClick: () => {
752
- closeContextMenu();
753
- setTabs([]);
754
- setInitialized(false);
755
- setCollapsed(true);
756
- }, children: "Close All" })
757
- ]
758
- }
759
- )
760
- ] });
761
- }
924
+ ) : /* @__PURE__ */ jsxs(Fragment2, { children: [
925
+ /* @__PURE__ */ jsx3("span", { className: `cli-panel-tab-dot ${(() => {
926
+ if (tab.id !== activeTabId) return "dot-idle";
927
+ if (statusExecutionState === "running") return "dot-running";
928
+ if (statusLastCommand && !statusLastCommand.success) return "dot-error";
929
+ return "dot-idle";
930
+ })()}` }),
931
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-tab-title", children: tab.title }),
932
+ /* @__PURE__ */ jsx3(
933
+ "button",
934
+ {
935
+ className: "cli-panel-tab-close-btn",
936
+ title: "Close tab",
937
+ onClick: (e) => {
938
+ e.stopPropagation();
939
+ closeTab(tab.id);
940
+ },
941
+ children: "\xD7"
942
+ }
943
+ )
944
+ ] })
945
+ },
946
+ tab.id
947
+ )) }),
948
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-add-tab", title: "New terminal", onClick: () => addTab(), children: "+" })
949
+ ] }),
950
+ /* @__PURE__ */ jsx3("div", { className: "cli-panel-instances", children: tabs.map((tab) => /* @__PURE__ */ jsx3("div", { className: "cli-panel-instance", style: { display: tab.id === activeTabId ? void 0 : "none" }, children: /* @__PURE__ */ jsx3("div", { className: `cli-panel-panes-container ${paneResizing ? "resizing" : ""}`, children: tab.panes.map((pane, i) => /* @__PURE__ */ jsxs(React3.Fragment, { children: [
951
+ i > 0 && /* @__PURE__ */ jsx3("div", { className: "cli-panel-pane-divider", onMouseDown: (e) => onPaneResizeStart(e, tab.id, i - 1), children: /* @__PURE__ */ jsx3("div", { className: "cli-panel-pane-divider-grip" }) }),
952
+ /* @__PURE__ */ jsxs(
953
+ "div",
954
+ {
955
+ className: `cli-panel-pane ${pane.id === activePaneId && tab.id === activeTabId ? "active-pane" : ""}`,
956
+ style: { flex: `${pane.widthPercent} 1 0` },
957
+ onClick: () => {
958
+ setActivePaneId(pane.id);
959
+ updateActiveTabId(tab.id);
960
+ },
961
+ children: [
962
+ tab.panes.length > 1 && /* @__PURE__ */ jsx3(
963
+ "button",
964
+ {
965
+ className: "cli-panel-pane-close-btn",
966
+ onClick: (e) => {
967
+ e.stopPropagation();
968
+ closePane(pane.id);
969
+ },
970
+ title: "Close pane",
971
+ children: "\xD7"
972
+ }
973
+ ),
974
+ /* @__PURE__ */ jsx3(CliContext.Provider, { value: { engine: null }, children: /* @__PURE__ */ jsx3(
975
+ Cli,
976
+ {
977
+ options,
978
+ modules,
979
+ processors,
980
+ services,
981
+ snapshot: pane.snapshot,
982
+ onReady: (engine) => engineMapRef.current.set(pane.id, engine)
983
+ }
984
+ ) })
985
+ ]
986
+ }
987
+ )
988
+ ] }, pane.id)) }) }, tab.id)) })
989
+ ] })
990
+ ]
991
+ }
992
+ ),
993
+ contextMenu.visible && /* @__PURE__ */ jsxs(
994
+ "div",
995
+ {
996
+ className: "cli-panel-context-menu",
997
+ style: { left: contextMenu.x, top: contextMenu.y },
998
+ onClick: (e) => e.stopPropagation(),
999
+ children: [
1000
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
1001
+ closeContextMenu();
1002
+ startRename(contextMenu.tabId);
1003
+ }, children: "Rename" }),
1004
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
1005
+ closeContextMenu();
1006
+ const tab = tabs.find((t) => t.id === contextMenu.tabId);
1007
+ if (!tab) return;
1008
+ const sourceEngine = engineMapRef.current.get(tab.panes[0]?.id);
1009
+ const snapshot = sourceEngine?.snapshot();
1010
+ const paneId = nextIdRef.current.pane++;
1011
+ const tabId = nextIdRef.current.tab++;
1012
+ const pane = { id: paneId, widthPercent: 100, snapshot };
1013
+ const newTab = { id: tabId, title: `${tab.title} (copy)`, isEditing: false, panes: [pane] };
1014
+ const idx = tabs.indexOf(tab);
1015
+ setTabs((prev) => {
1016
+ const next = [...prev];
1017
+ next.splice(idx + 1, 0, newTab);
1018
+ return next;
1019
+ });
1020
+ updateActiveTabId(tabId);
1021
+ setActivePaneId(paneId);
1022
+ props.onTabAdded?.({ tabId });
1023
+ }, children: "Duplicate" }),
1024
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
1025
+ closeContextMenu();
1026
+ splitPane(contextMenu.tabId);
1027
+ }, children: "Split Right" }),
1028
+ /* @__PURE__ */ jsx3("div", { className: "cli-panel-context-menu-separator" }),
1029
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
1030
+ closeContextMenu();
1031
+ closeTab(contextMenu.tabId);
1032
+ }, children: "Close" }),
1033
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", disabled: tabs.length <= 1, onClick: () => {
1034
+ closeContextMenu();
1035
+ setTabs((prev) => prev.filter((t) => t.id === contextMenu.tabId));
1036
+ updateActiveTabId(contextMenu.tabId);
1037
+ }, children: "Close Others" }),
1038
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item", onClick: () => {
1039
+ const id = contextMenu.tabId;
1040
+ closeContextMenu();
1041
+ setTabs((prev) => {
1042
+ const idx = prev.findIndex((t) => t.id === id);
1043
+ if (idx === -1) return prev;
1044
+ return prev.slice(0, idx + 1);
1045
+ });
1046
+ }, children: "Close to the Right" }),
1047
+ /* @__PURE__ */ jsx3("div", { className: "cli-panel-context-menu-separator" }),
1048
+ /* @__PURE__ */ jsx3("button", { className: "cli-panel-context-menu-item destructive", onClick: () => {
1049
+ closeContextMenu();
1050
+ setTabs([]);
1051
+ setInitialized(false);
1052
+ updateCollapsed(true);
1053
+ }, children: "Close All" })
1054
+ ]
1055
+ }
1056
+ ),
1057
+ servicesDropdownOpen && statusServiceCount.total > 0 && /* @__PURE__ */ jsxs(
1058
+ "div",
1059
+ {
1060
+ className: "cli-panel-services-dropdown",
1061
+ style: (() => {
1062
+ const el = servicesDropdownRef.current;
1063
+ if (!el) return {};
1064
+ const rect = el.getBoundingClientRect();
1065
+ return position === "top" ? { position: "fixed", top: rect.bottom + 4, left: rect.left, zIndex: 1100 } : { position: "fixed", bottom: window.innerHeight - rect.top + 4, left: rect.left, zIndex: 1100 };
1066
+ })(),
1067
+ onClick: (e) => e.stopPropagation(),
1068
+ children: [
1069
+ /* @__PURE__ */ jsx3("div", { className: "cli-panel-services-dropdown-header", children: "Background Services" }),
1070
+ /* @__PURE__ */ jsx3("div", { className: "cli-panel-services-dropdown-list", children: statusServiceDetails.map((svc, i) => /* @__PURE__ */ jsxs("div", { className: "cli-panel-services-dropdown-item", children: [
1071
+ /* @__PURE__ */ jsx3("span", { className: `cli-panel-svc-dot ${svc.status === "running" ? "svc-running" : "svc-stopped"}` }),
1072
+ /* @__PURE__ */ jsxs("div", { className: "cli-panel-svc-info", children: [
1073
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-svc-name", children: svc.name }),
1074
+ svc.description && /* @__PURE__ */ jsx3("span", { className: "cli-panel-svc-desc", children: svc.description })
1075
+ ] }),
1076
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-svc-status", children: svc.status })
1077
+ ] }, i)) }),
1078
+ statusServiceDetails.length === 0 && /* @__PURE__ */ jsx3("div", { className: "cli-panel-services-dropdown-empty", children: "No services registered" })
1079
+ ]
1080
+ }
1081
+ ),
1082
+ serversDropdownOpen && statusServerState !== "none" && /* @__PURE__ */ jsxs(
1083
+ "div",
1084
+ {
1085
+ className: "cli-panel-services-dropdown",
1086
+ style: (() => {
1087
+ const el = serversDropdownRef.current;
1088
+ if (!el) return {};
1089
+ const rect = el.getBoundingClientRect();
1090
+ return position === "top" ? { position: "fixed", top: rect.bottom + 4, left: rect.left, zIndex: 1100 } : { position: "fixed", bottom: window.innerHeight - rect.top + 4, left: rect.left, zIndex: 1100 };
1091
+ })(),
1092
+ onClick: (e) => e.stopPropagation(),
1093
+ children: [
1094
+ /* @__PURE__ */ jsx3("div", { className: "cli-panel-services-dropdown-header", children: "Server Connections" }),
1095
+ /* @__PURE__ */ jsx3("div", { className: "cli-panel-services-dropdown-list", children: statusServerDetails.map((srv, i) => /* @__PURE__ */ jsxs("div", { className: "cli-panel-services-dropdown-item", children: [
1096
+ /* @__PURE__ */ jsx3("span", { className: `cli-panel-svc-dot ${srv.connected ? "svc-running" : "svc-stopped"}` }),
1097
+ /* @__PURE__ */ jsxs("div", { className: "cli-panel-svc-info", children: [
1098
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-svc-name", children: srv.name }),
1099
+ srv.url && /* @__PURE__ */ jsx3("span", { className: "cli-panel-svc-desc", children: srv.url })
1100
+ ] }),
1101
+ /* @__PURE__ */ jsxs("div", { className: "cli-panel-srv-meta", children: [
1102
+ /* @__PURE__ */ jsx3("span", { className: "cli-panel-svc-status", children: srv.connected ? "connected" : "disconnected" }),
1103
+ srv.apiVersion && /* @__PURE__ */ jsxs("span", { className: "cli-panel-svc-desc", children: [
1104
+ "v",
1105
+ srv.apiVersion
1106
+ ] }),
1107
+ srv.commandCount && /* @__PURE__ */ jsxs("span", { className: "cli-panel-svc-desc", children: [
1108
+ srv.commandCount,
1109
+ " cmds"
1110
+ ] })
1111
+ ] })
1112
+ ] }, i)) }),
1113
+ statusServerDetails.length === 0 && /* @__PURE__ */ jsx3("div", { className: "cli-panel-services-dropdown-empty", children: "No servers configured" })
1114
+ ]
1115
+ }
1116
+ )
1117
+ ] });
1118
+ }
1119
+ );
762
1120
 
763
1121
  // src/CliProvider.tsx
764
1122
  import { useRef as useRef4 } from "react";