@qodalis/vue-cli 2.0.0-beta.11 → 2.0.0-beta.13

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 CHANGED
@@ -304,7 +304,7 @@ var CliPanel = (0, import_vue3.defineComponent)({
304
304
  ],
305
305
  setup(props, { expose, emit }) {
306
306
  const config = (0, import_vue3.inject)(CliConfigKey, null);
307
- const mergedOptions = (0, import_vue3.computed)(() => props.options ?? config?.options);
307
+ const mergedOptions = (0, import_vue3.computed)(() => props.options ? { ...config?.options, ...props.options } : config?.options);
308
308
  const mergedModules = (0, import_vue3.computed)(() => props.modules ?? config?.modules);
309
309
  const mergedProcessors = (0, import_vue3.computed)(() => props.processors ?? config?.processors);
310
310
  const mergedServices = (0, import_vue3.computed)(() => props.services ?? config?.services);
@@ -386,6 +386,107 @@ var CliPanel = (0, import_vue3.defineComponent)({
386
386
  };
387
387
  const panelResizing = (0, import_vue3.ref)(false);
388
388
  let panelResizeState = { startY: 0, startHeight: 0, startX: 0, startWidth: 0 };
389
+ const statusExecutionState = (0, import_vue3.ref)("idle");
390
+ const statusLastCommand = (0, import_vue3.ref)(null);
391
+ const statusServiceCount = (0, import_vue3.ref)({ running: 0, total: 0 });
392
+ const statusServiceDetails = (0, import_vue3.ref)([]);
393
+ const statusServerState = (0, import_vue3.ref)("none");
394
+ const statusServerDetails = (0, import_vue3.ref)([]);
395
+ const statusUptime = (0, import_vue3.ref)(0);
396
+ const notification = (0, import_vue3.ref)(null);
397
+ const servicesDropdownOpen = (0, import_vue3.ref)(false);
398
+ const serversDropdownOpen = (0, import_vue3.ref)(false);
399
+ const servicesDropdownTriggerRect = (0, import_vue3.ref)(null);
400
+ const serversDropdownTriggerRect = (0, import_vue3.ref)(null);
401
+ const formattedUptime = (0, import_vue3.computed)(() => {
402
+ const mins = Math.floor(statusUptime.value / 6e4);
403
+ if (mins < 60) return `${mins}m`;
404
+ const hrs = Math.floor(mins / 60);
405
+ return `${hrs}h${mins % 60}m`;
406
+ });
407
+ let execPollTimer;
408
+ let globalPollTimer;
409
+ function startStatusPolling() {
410
+ stopStatusPolling();
411
+ execPollTimer = setInterval(() => {
412
+ const tab = tabs.value.find((t) => t.id === resolvedActiveTabId.value);
413
+ if (!tab) return;
414
+ const engine = engineMap.get(tab.panes[0]?.id);
415
+ if (!engine) return;
416
+ const context = engine.getContext();
417
+ if (!context) return;
418
+ const running = !!context.isExecuting || !!context.contextProcessor;
419
+ statusExecutionState.value = running ? "running" : "idle";
420
+ const result = context.lastCommandResult;
421
+ statusLastCommand.value = result ? { name: result.command, success: result.success } : null;
422
+ const notif = context.notifier?.current;
423
+ notification.value = notif || null;
424
+ }, 300);
425
+ globalPollTimer = setInterval(() => {
426
+ const tab = tabs.value.find((t) => t.id === resolvedActiveTabId.value);
427
+ if (!tab) return;
428
+ const engine = engineMap.get(tab.panes[0]?.id);
429
+ if (!engine) return;
430
+ const context = engine.getContext();
431
+ if (!context) return;
432
+ try {
433
+ const services = context.backgroundServices?.list() ?? [];
434
+ statusServiceCount.value = { running: services.filter((s) => s.status === "running").length, total: services.length };
435
+ statusServiceDetails.value = services.map((s) => ({ name: s.name, status: s.status, description: s.description }));
436
+ } catch {
437
+ }
438
+ try {
439
+ const serverManager = context.services?.get?.("cli-server-manager");
440
+ const details = [];
441
+ if (serverManager?.connections?.size > 0) {
442
+ let anyConnected = false;
443
+ for (const [name, conn] of serverManager.connections) {
444
+ if (conn.connected) anyConnected = true;
445
+ details.push({
446
+ name,
447
+ url: conn.config?.url ?? "",
448
+ connected: !!conn.connected,
449
+ apiVersion: conn.connected ? conn.apiVersion : void 0,
450
+ commandCount: conn.connected ? conn.commands?.length : void 0
451
+ });
452
+ }
453
+ statusServerState.value = anyConnected ? "connected" : "disconnected";
454
+ } else {
455
+ const configuredServers = engine.options?.servers;
456
+ if (Array.isArray(configuredServers) && configuredServers.length > 0) {
457
+ for (const srv of configuredServers) {
458
+ if (srv.enabled === false) continue;
459
+ details.push({
460
+ name: srv.name,
461
+ url: srv.url ?? "",
462
+ connected: false
463
+ });
464
+ }
465
+ statusServerState.value = "disconnected";
466
+ } else {
467
+ statusServerState.value = "none";
468
+ }
469
+ }
470
+ statusServerDetails.value = details;
471
+ } catch {
472
+ }
473
+ statusUptime.value = engine.startedAt ? Date.now() - engine.startedAt : 0;
474
+ }, 2e3);
475
+ }
476
+ function stopStatusPolling() {
477
+ if (execPollTimer) {
478
+ clearInterval(execPollTimer);
479
+ execPollTimer = void 0;
480
+ }
481
+ if (globalPollTimer) {
482
+ clearInterval(globalPollTimer);
483
+ globalPollTimer = void 0;
484
+ }
485
+ }
486
+ (0, import_vue3.watch)(initialized, (val) => {
487
+ if (val) startStatusPolling();
488
+ else stopStatusPolling();
489
+ });
389
490
  function addTab(title) {
390
491
  const tabId = nextTabId++;
391
492
  const paneId = nextPaneId++;
@@ -462,6 +563,10 @@ var CliPanel = (0, import_vue3.defineComponent)({
462
563
  tabs.value = tabs.value.map((t) => {
463
564
  if (t.id !== targetTabId) return t;
464
565
  const newPanes = [...t.panes, { id: paneId, widthPercent: 0 }];
566
+ const evenWidth = 100 / newPanes.length;
567
+ newPanes.forEach((p) => {
568
+ p.widthPercent = evenWidth;
569
+ });
465
570
  normalizePanes(newPanes);
466
571
  return { ...t, panes: newPanes };
467
572
  });
@@ -604,6 +709,7 @@ var CliPanel = (0, import_vue3.defineComponent)({
604
709
  (0, import_vue3.onBeforeUnmount)(() => {
605
710
  document.removeEventListener("mousemove", onPaneResizeMove);
606
711
  document.removeEventListener("mouseup", onPaneResizeEnd);
712
+ stopStatusPolling();
607
713
  });
608
714
  function toggleMaximize() {
609
715
  if (!resolvedMaximized.value) {
@@ -639,6 +745,8 @@ var CliPanel = (0, import_vue3.defineComponent)({
639
745
  const positionDropdownOpen = (0, import_vue3.ref)(false);
640
746
  function closePositionDropdown() {
641
747
  positionDropdownOpen.value = false;
748
+ servicesDropdownOpen.value = false;
749
+ serversDropdownOpen.value = false;
642
750
  }
643
751
  function togglePositionDropdown(e) {
644
752
  e.stopPropagation();
@@ -765,6 +873,105 @@ var CliPanel = (0, import_vue3.defineComponent)({
765
873
  ]),
766
874
  "CLI"
767
875
  ]),
876
+ // Status indicators (bottom/top only)
877
+ resolvedPosition.value === "bottom" || resolvedPosition.value === "top" ? (0, import_vue3.h)("div", { class: "cli-panel-status-indicators" }, [
878
+ // Execution state
879
+ (0, import_vue3.h)("span", { class: ["cli-panel-status-item", statusExecutionState.value === "running" ? "status-running" : ""].filter(Boolean).join(" ") }, [
880
+ (0, import_vue3.h)("span", { class: ["cli-panel-status-dot", statusExecutionState.value === "running" ? "dot-running" : "dot-idle"].join(" ") }),
881
+ (0, import_vue3.h)("span", { class: "cli-panel-status-label" }, statusExecutionState.value)
882
+ ]),
883
+ // Background services
884
+ statusServiceCount.value.total > 0 ? (0, import_vue3.h)("span", {
885
+ class: "cli-panel-status-item status-clickable",
886
+ onClick: (e) => {
887
+ e.stopPropagation();
888
+ servicesDropdownTriggerRect.value = e.currentTarget.getBoundingClientRect();
889
+ servicesDropdownOpen.value = !servicesDropdownOpen.value;
890
+ serversDropdownOpen.value = false;
891
+ }
892
+ }, [
893
+ (0, import_vue3.h)("span", { class: "cli-panel-status-icon", innerHTML: "&#9881;" }),
894
+ (0, import_vue3.h)("span", { class: "cli-panel-status-label" }, `${statusServiceCount.value.running}/${statusServiceCount.value.total} services`)
895
+ ]) : null,
896
+ // Last command
897
+ statusLastCommand.value ? (0, import_vue3.h)("span", { class: "cli-panel-status-item" }, [
898
+ (0, import_vue3.h)("span", { class: ["cli-panel-status-icon", statusLastCommand.value.success ? "status-success" : "status-error"].join(" "), innerHTML: statusLastCommand.value.success ? "&#10003;" : "&#10005;" }),
899
+ (0, import_vue3.h)("span", { class: "cli-panel-status-label" }, statusLastCommand.value.name)
900
+ ]) : null,
901
+ // Server connection
902
+ statusServerState.value !== "none" ? (0, import_vue3.h)("span", {
903
+ class: "cli-panel-status-item status-clickable",
904
+ onClick: (e) => {
905
+ e.stopPropagation();
906
+ serversDropdownTriggerRect.value = e.currentTarget.getBoundingClientRect();
907
+ serversDropdownOpen.value = !serversDropdownOpen.value;
908
+ servicesDropdownOpen.value = false;
909
+ }
910
+ }, [
911
+ (0, import_vue3.h)("span", { class: ["cli-panel-status-dot", statusServerState.value === "connected" ? "dot-idle" : "dot-error"].join(" ") }),
912
+ (0, import_vue3.h)("span", { class: "cli-panel-status-label" }, `${statusServerDetails.value.filter((s) => s.connected).length}/${statusServerDetails.value.length} servers`)
913
+ ]) : null,
914
+ // Uptime
915
+ statusUptime.value > 0 ? (0, import_vue3.h)("span", { class: "cli-panel-status-item status-muted" }, [
916
+ (0, import_vue3.h)("span", { class: "cli-panel-status-icon", innerHTML: "&uarr;" }),
917
+ (0, import_vue3.h)("span", { class: "cli-panel-status-label" }, formattedUptime.value)
918
+ ]) : null,
919
+ // Custom notification
920
+ notification.value ? (0, import_vue3.h)("span", { class: `cli-panel-status-item status-text level-${notification.value.level}` }, [
921
+ (0, import_vue3.h)("span", { class: "cli-panel-status-label" }, notification.value.message)
922
+ ]) : null
923
+ ].filter(Boolean)) : null,
924
+ // Compact status indicators (left/right positions — CSS controls visibility)
925
+ (0, import_vue3.h)("div", { class: "cli-panel-status-indicators-compact" }, [
926
+ // Execution state
927
+ (0, import_vue3.h)("span", { class: "cli-panel-status-compact-item", title: statusExecutionState.value }, [
928
+ (0, import_vue3.h)("span", { class: ["cli-panel-status-dot", statusExecutionState.value === "running" ? "dot-running" : "dot-idle"].join(" ") })
929
+ ]),
930
+ // Background services
931
+ statusServiceCount.value.total > 0 ? (0, import_vue3.h)("span", {
932
+ class: "cli-panel-status-compact-item status-clickable",
933
+ title: `${statusServiceCount.value.running}/${statusServiceCount.value.total} services`,
934
+ onClick: (e) => {
935
+ e.stopPropagation();
936
+ servicesDropdownTriggerRect.value = e.currentTarget.getBoundingClientRect();
937
+ servicesDropdownOpen.value = !servicesDropdownOpen.value;
938
+ serversDropdownOpen.value = false;
939
+ }
940
+ }, [
941
+ (0, import_vue3.h)("span", { class: "cli-panel-status-icon", innerHTML: "&#9881;" })
942
+ ]) : null,
943
+ // Last command
944
+ statusLastCommand.value ? (0, import_vue3.h)("span", {
945
+ class: "cli-panel-status-compact-item",
946
+ title: `${statusLastCommand.value.success ? "\u2713" : "\u2717"} ${statusLastCommand.value.name}`
947
+ }, [
948
+ (0, import_vue3.h)("span", {
949
+ class: ["cli-panel-status-icon", statusLastCommand.value.success ? "status-success" : "status-error"].join(" "),
950
+ innerHTML: statusLastCommand.value.success ? "&#10003;" : "&#10005;"
951
+ })
952
+ ]) : null,
953
+ // Server connection
954
+ statusServerState.value !== "none" ? (0, import_vue3.h)("span", {
955
+ class: "cli-panel-status-compact-item status-clickable",
956
+ title: `${statusServerDetails.value.filter((s) => s.connected).length}/${statusServerDetails.value.length} servers`,
957
+ onClick: (e) => {
958
+ e.stopPropagation();
959
+ serversDropdownTriggerRect.value = e.currentTarget.getBoundingClientRect();
960
+ serversDropdownOpen.value = !serversDropdownOpen.value;
961
+ servicesDropdownOpen.value = false;
962
+ }
963
+ }, [
964
+ (0, import_vue3.h)("span", { class: ["cli-panel-status-dot", statusServerState.value === "connected" ? "dot-idle" : "dot-error"].join(" ") })
965
+ ]) : null,
966
+ // Uptime
967
+ statusUptime.value > 0 ? (0, import_vue3.h)("span", { class: "cli-panel-status-compact-item status-muted", title: formattedUptime.value }, [
968
+ (0, import_vue3.h)("span", { class: "cli-panel-status-icon", innerHTML: "&uarr;" })
969
+ ]) : null,
970
+ // Notification
971
+ notification.value ? (0, import_vue3.h)("span", { class: "cli-panel-status-compact-item", title: notification.value.message }, [
972
+ (0, import_vue3.h)("span", { class: `cli-panel-status-compact-dot level-${notification.value.level}` })
973
+ ]) : null
974
+ ].filter(Boolean)),
768
975
  (0, import_vue3.h)("div", { class: "cli-panel-action-buttons" }, [
769
976
  (0, import_vue3.h)("div", {
770
977
  class: "cli-panel-btn-position-wrapper",
@@ -823,7 +1030,8 @@ var CliPanel = (0, import_vue3.defineComponent)({
823
1030
  [closeIcon()]
824
1031
  ) : null
825
1032
  ])
826
- ])
1033
+ ]),
1034
+ (0, import_vue3.h)("div", { class: ["cli-panel-glow-line", statusExecutionState.value === "running" ? "glow-active" : ""].filter(Boolean).join(" ") })
827
1035
  ]);
828
1036
  const contentEl = initialized.value ? (0, import_vue3.h)("div", { class: "cli-panel-content", style: resolvedCollapsed.value ? { display: "none" } : void 0 }, [
829
1037
  // Tab bar
@@ -876,6 +1084,12 @@ var CliPanel = (0, import_vue3.defineComponent)({
876
1084
  onDblclick: (e) => e.stopPropagation()
877
1085
  })
878
1086
  ] : [
1087
+ (0, import_vue3.h)("span", { class: ["cli-panel-tab-dot", (() => {
1088
+ if (tab.id !== resolvedActiveTabId.value) return "dot-idle";
1089
+ if (statusExecutionState.value === "running") return "dot-running";
1090
+ if (statusLastCommand.value && !statusLastCommand.value.success) return "dot-error";
1091
+ return "dot-idle";
1092
+ })()].join(" ") }),
879
1093
  (0, import_vue3.h)(
880
1094
  "span",
881
1095
  {
@@ -906,7 +1120,7 @@ var CliPanel = (0, import_vue3.defineComponent)({
906
1120
  {
907
1121
  class: "cli-panel-add-tab",
908
1122
  title: "New terminal",
909
- onClick: addTab
1123
+ onClick: () => addTab()
910
1124
  },
911
1125
  "+"
912
1126
  )
@@ -1157,6 +1371,82 @@ var CliPanel = (0, import_vue3.defineComponent)({
1157
1371
  (0, import_vue3.h)("span", { class: "cli-panel-hide-tab-label" }, "CLI"),
1158
1372
  hideTabChevron(resolvedPosition.value)
1159
1373
  ]) : null;
1374
+ const servicesDropdownEl = servicesDropdownOpen.value && statusServiceCount.value.total > 0 ? (0, import_vue3.h)("div", {
1375
+ class: "cli-panel-services-dropdown",
1376
+ style: (() => {
1377
+ const rect = servicesDropdownTriggerRect.value;
1378
+ if (!rect) return {};
1379
+ const base = { position: "fixed", zIndex: 1100 };
1380
+ switch (resolvedPosition.value) {
1381
+ case "top":
1382
+ return { ...base, top: `${rect.bottom + 4}px`, left: `${rect.left}px` };
1383
+ case "left":
1384
+ return { ...base, top: `${rect.top}px`, left: `${rect.right + 4}px` };
1385
+ case "right":
1386
+ return { ...base, top: `${rect.top}px`, right: `${window.innerWidth - rect.left + 4}px` };
1387
+ default:
1388
+ return { ...base, bottom: `${window.innerHeight - rect.top + 4}px`, left: `${rect.left}px` };
1389
+ }
1390
+ })(),
1391
+ onClick: (e) => e.stopPropagation()
1392
+ }, [
1393
+ (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-header" }, "Background Services"),
1394
+ (0, import_vue3.h)(
1395
+ "div",
1396
+ { class: "cli-panel-services-dropdown-list" },
1397
+ statusServiceDetails.value.map(
1398
+ (svc, i) => (0, import_vue3.h)("div", { key: i, class: "cli-panel-services-dropdown-item" }, [
1399
+ (0, import_vue3.h)("span", { class: ["cli-panel-svc-dot", svc.status === "running" ? "svc-running" : "svc-stopped"].join(" ") }),
1400
+ (0, import_vue3.h)("div", { class: "cli-panel-svc-info" }, [
1401
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-name" }, svc.name),
1402
+ svc.description ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, svc.description) : null
1403
+ ].filter(Boolean)),
1404
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-status" }, svc.status)
1405
+ ])
1406
+ )
1407
+ ),
1408
+ statusServiceDetails.value.length === 0 ? (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-empty" }, "No services registered") : null
1409
+ ].filter(Boolean)) : null;
1410
+ const serversDropdownEl = serversDropdownOpen.value && statusServerState.value !== "none" ? (0, import_vue3.h)("div", {
1411
+ class: "cli-panel-services-dropdown",
1412
+ style: (() => {
1413
+ const rect = serversDropdownTriggerRect.value;
1414
+ if (!rect) return {};
1415
+ const base = { position: "fixed", zIndex: 1100 };
1416
+ switch (resolvedPosition.value) {
1417
+ case "top":
1418
+ return { ...base, top: `${rect.bottom + 4}px`, left: `${rect.left}px` };
1419
+ case "left":
1420
+ return { ...base, top: `${rect.top}px`, left: `${rect.right + 4}px` };
1421
+ case "right":
1422
+ return { ...base, top: `${rect.top}px`, right: `${window.innerWidth - rect.left + 4}px` };
1423
+ default:
1424
+ return { ...base, bottom: `${window.innerHeight - rect.top + 4}px`, left: `${rect.left}px` };
1425
+ }
1426
+ })(),
1427
+ onClick: (e) => e.stopPropagation()
1428
+ }, [
1429
+ (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-header" }, "Server Connections"),
1430
+ (0, import_vue3.h)(
1431
+ "div",
1432
+ { class: "cli-panel-services-dropdown-list" },
1433
+ statusServerDetails.value.map(
1434
+ (srv, i) => (0, import_vue3.h)("div", { key: i, class: "cli-panel-services-dropdown-item" }, [
1435
+ (0, import_vue3.h)("span", { class: ["cli-panel-svc-dot", srv.connected ? "svc-running" : "svc-stopped"].join(" ") }),
1436
+ (0, import_vue3.h)("div", { class: "cli-panel-svc-info" }, [
1437
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-name" }, srv.name),
1438
+ srv.url ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, srv.url) : null
1439
+ ].filter(Boolean)),
1440
+ (0, import_vue3.h)("div", { class: "cli-panel-srv-meta" }, [
1441
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-status" }, srv.connected ? "connected" : "disconnected"),
1442
+ srv.apiVersion ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, `v${srv.apiVersion}`) : null,
1443
+ srv.commandCount ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, `${srv.commandCount} cmds`) : null
1444
+ ].filter(Boolean))
1445
+ ])
1446
+ )
1447
+ ),
1448
+ statusServerDetails.value.length === 0 ? (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-empty" }, "No servers configured") : null
1449
+ ].filter(Boolean)) : null;
1160
1450
  return (0, import_vue3.h)("div", {}, [
1161
1451
  hideTabEl,
1162
1452
  (0, import_vue3.h)(
@@ -1171,7 +1461,9 @@ var CliPanel = (0, import_vue3.defineComponent)({
1171
1461
  },
1172
1462
  [headerEl, contentEl]
1173
1463
  ),
1174
- contextMenuEl
1464
+ contextMenuEl,
1465
+ servicesDropdownEl,
1466
+ serversDropdownEl
1175
1467
  ]);
1176
1468
  };
1177
1469
  }