@qodalis/vue-cli 2.0.0-beta.11 → 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.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 statusText = (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 text = context.getStatusText?.();
423
+ statusText.value = text || 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,54 @@ 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 status text
920
+ statusText.value ? (0, import_vue3.h)("span", { class: "cli-panel-status-item status-text" }, [
921
+ (0, import_vue3.h)("span", { class: "cli-panel-status-label" }, statusText.value)
922
+ ]) : null
923
+ ].filter(Boolean)) : null,
768
924
  (0, import_vue3.h)("div", { class: "cli-panel-action-buttons" }, [
769
925
  (0, import_vue3.h)("div", {
770
926
  class: "cli-panel-btn-position-wrapper",
@@ -823,7 +979,8 @@ var CliPanel = (0, import_vue3.defineComponent)({
823
979
  [closeIcon()]
824
980
  ) : null
825
981
  ])
826
- ])
982
+ ]),
983
+ (0, import_vue3.h)("div", { class: ["cli-panel-glow-line", statusExecutionState.value === "running" ? "glow-active" : ""].filter(Boolean).join(" ") })
827
984
  ]);
828
985
  const contentEl = initialized.value ? (0, import_vue3.h)("div", { class: "cli-panel-content", style: resolvedCollapsed.value ? { display: "none" } : void 0 }, [
829
986
  // Tab bar
@@ -876,6 +1033,12 @@ var CliPanel = (0, import_vue3.defineComponent)({
876
1033
  onDblclick: (e) => e.stopPropagation()
877
1034
  })
878
1035
  ] : [
1036
+ (0, import_vue3.h)("span", { class: ["cli-panel-tab-dot", (() => {
1037
+ if (tab.id !== resolvedActiveTabId.value) return "dot-idle";
1038
+ if (statusExecutionState.value === "running") return "dot-running";
1039
+ if (statusLastCommand.value && !statusLastCommand.value.success) return "dot-error";
1040
+ return "dot-idle";
1041
+ })()].join(" ") }),
879
1042
  (0, import_vue3.h)(
880
1043
  "span",
881
1044
  {
@@ -906,7 +1069,7 @@ var CliPanel = (0, import_vue3.defineComponent)({
906
1069
  {
907
1070
  class: "cli-panel-add-tab",
908
1071
  title: "New terminal",
909
- onClick: addTab
1072
+ onClick: () => addTab()
910
1073
  },
911
1074
  "+"
912
1075
  )
@@ -1157,6 +1320,62 @@ var CliPanel = (0, import_vue3.defineComponent)({
1157
1320
  (0, import_vue3.h)("span", { class: "cli-panel-hide-tab-label" }, "CLI"),
1158
1321
  hideTabChevron(resolvedPosition.value)
1159
1322
  ]) : null;
1323
+ const servicesDropdownEl = servicesDropdownOpen.value && statusServiceCount.value.total > 0 ? (0, import_vue3.h)("div", {
1324
+ class: "cli-panel-services-dropdown",
1325
+ style: (() => {
1326
+ const rect = servicesDropdownTriggerRect.value;
1327
+ if (!rect) return {};
1328
+ return resolvedPosition.value === "top" ? { position: "fixed", top: `${rect.bottom + 4}px`, left: `${rect.left}px`, zIndex: 1100 } : { position: "fixed", bottom: `${window.innerHeight - rect.top + 4}px`, left: `${rect.left}px`, zIndex: 1100 };
1329
+ })(),
1330
+ onClick: (e) => e.stopPropagation()
1331
+ }, [
1332
+ (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-header" }, "Background Services"),
1333
+ (0, import_vue3.h)(
1334
+ "div",
1335
+ { class: "cli-panel-services-dropdown-list" },
1336
+ statusServiceDetails.value.map(
1337
+ (svc, i) => (0, import_vue3.h)("div", { key: i, class: "cli-panel-services-dropdown-item" }, [
1338
+ (0, import_vue3.h)("span", { class: ["cli-panel-svc-dot", svc.status === "running" ? "svc-running" : "svc-stopped"].join(" ") }),
1339
+ (0, import_vue3.h)("div", { class: "cli-panel-svc-info" }, [
1340
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-name" }, svc.name),
1341
+ svc.description ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, svc.description) : null
1342
+ ].filter(Boolean)),
1343
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-status" }, svc.status)
1344
+ ])
1345
+ )
1346
+ ),
1347
+ statusServiceDetails.value.length === 0 ? (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-empty" }, "No services registered") : null
1348
+ ].filter(Boolean)) : null;
1349
+ const serversDropdownEl = serversDropdownOpen.value && statusServerState.value !== "none" ? (0, import_vue3.h)("div", {
1350
+ class: "cli-panel-services-dropdown",
1351
+ style: (() => {
1352
+ const rect = serversDropdownTriggerRect.value;
1353
+ if (!rect) return {};
1354
+ return resolvedPosition.value === "top" ? { position: "fixed", top: `${rect.bottom + 4}px`, left: `${rect.left}px`, zIndex: 1100 } : { position: "fixed", bottom: `${window.innerHeight - rect.top + 4}px`, left: `${rect.left}px`, zIndex: 1100 };
1355
+ })(),
1356
+ onClick: (e) => e.stopPropagation()
1357
+ }, [
1358
+ (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-header" }, "Server Connections"),
1359
+ (0, import_vue3.h)(
1360
+ "div",
1361
+ { class: "cli-panel-services-dropdown-list" },
1362
+ statusServerDetails.value.map(
1363
+ (srv, i) => (0, import_vue3.h)("div", { key: i, class: "cli-panel-services-dropdown-item" }, [
1364
+ (0, import_vue3.h)("span", { class: ["cli-panel-svc-dot", srv.connected ? "svc-running" : "svc-stopped"].join(" ") }),
1365
+ (0, import_vue3.h)("div", { class: "cli-panel-svc-info" }, [
1366
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-name" }, srv.name),
1367
+ srv.url ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, srv.url) : null
1368
+ ].filter(Boolean)),
1369
+ (0, import_vue3.h)("div", { class: "cli-panel-srv-meta" }, [
1370
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-status" }, srv.connected ? "connected" : "disconnected"),
1371
+ srv.apiVersion ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, `v${srv.apiVersion}`) : null,
1372
+ srv.commandCount ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, `${srv.commandCount} cmds`) : null
1373
+ ].filter(Boolean))
1374
+ ])
1375
+ )
1376
+ ),
1377
+ statusServerDetails.value.length === 0 ? (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-empty" }, "No servers configured") : null
1378
+ ].filter(Boolean)) : null;
1160
1379
  return (0, import_vue3.h)("div", {}, [
1161
1380
  hideTabEl,
1162
1381
  (0, import_vue3.h)(
@@ -1171,7 +1390,9 @@ var CliPanel = (0, import_vue3.defineComponent)({
1171
1390
  },
1172
1391
  [headerEl, contentEl]
1173
1392
  ),
1174
- contextMenuEl
1393
+ contextMenuEl,
1394
+ servicesDropdownEl,
1395
+ serversDropdownEl
1175
1396
  ]);
1176
1397
  };
1177
1398
  }