@qodalis/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.
@@ -171,6 +171,8 @@
171
171
  overflow-x: auto;
172
172
  overflow-y: hidden;
173
173
  flex-shrink: 0;
174
+ scrollbar-width: thin;
175
+ scrollbar-color: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.3)) transparent;
174
176
  }
175
177
 
176
178
  .cli-panel-tabs::-webkit-scrollbar {
@@ -809,6 +811,321 @@
809
811
  left: auto;
810
812
  }
811
813
 
814
+ /* ─── Status indicators ──────────────────────────────────── */
815
+
816
+ .cli-panel-status-indicators {
817
+ display: flex;
818
+ align-items: center;
819
+ gap: 14px;
820
+ margin-left: 24px;
821
+ font-size: 12px;
822
+ overflow: hidden;
823
+ white-space: nowrap;
824
+ }
825
+
826
+ .cli-panel-status-item {
827
+ display: flex;
828
+ align-items: center;
829
+ gap: 5px;
830
+ color: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.6));
831
+ }
832
+
833
+ .cli-panel-status-dot {
834
+ width: 6px;
835
+ height: 6px;
836
+ border-radius: 50%;
837
+ flex-shrink: 0;
838
+ background: var(--cli-status-neutral, #6b7280);
839
+ }
840
+
841
+ .cli-panel-status-dot.dot-idle {
842
+ background: var(--cli-status-idle, #3fb950);
843
+ }
844
+
845
+ .cli-panel-status-dot.dot-running {
846
+ background: var(--cli-status-running, #f0883e);
847
+ animation: cliStatusPulse 1.5s ease-in-out infinite;
848
+ }
849
+
850
+ .cli-panel-status-dot.dot-error {
851
+ background: var(--cli-status-error, #f85149);
852
+ }
853
+
854
+ .cli-panel-status-icon {
855
+ flex-shrink: 0;
856
+ }
857
+
858
+ .cli-panel-status-icon.status-success {
859
+ color: var(--cli-status-idle, #3fb950);
860
+ }
861
+
862
+ .cli-panel-status-icon.status-error {
863
+ color: var(--cli-status-error, #f85149);
864
+ }
865
+
866
+ .cli-panel-status-label {
867
+ overflow: hidden;
868
+ text-overflow: ellipsis;
869
+ }
870
+
871
+ .cli-panel-status-item.status-muted {
872
+ color: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.4));
873
+ }
874
+
875
+ .cli-panel-status-item.status-text {
876
+ color: var(--cli-panel-accent, #818cf8);
877
+ max-width: 200px;
878
+ }
879
+
880
+ .cli-panel-status-item.status-running {
881
+ color: var(--cli-status-running, #f0883e);
882
+ }
883
+
884
+ .cli-panel-status-item.status-clickable {
885
+ cursor: pointer;
886
+ border-radius: 4px;
887
+ padding: 2px 6px;
888
+ margin: -2px -6px;
889
+ transition: background-color 0.15s ease;
890
+ }
891
+
892
+ .cli-panel-status-item.status-clickable:hover {
893
+ background-color: var(--cli-btn-hover-bg, rgba(129, 140, 248, 0.12));
894
+ }
895
+
896
+ /* ─── Tab dot ────────────────────────────────────────────── */
897
+
898
+ .cli-panel-tab-dot {
899
+ width: 6px;
900
+ height: 6px;
901
+ border-radius: 50%;
902
+ flex-shrink: 0;
903
+ background: var(--cli-status-idle, #3fb950);
904
+ }
905
+
906
+ .cli-panel-tab-dot.dot-running {
907
+ background: var(--cli-status-running, #f0883e);
908
+ animation: cliStatusPulse 1.5s ease-in-out infinite;
909
+ }
910
+
911
+ .cli-panel-tab-dot.dot-error {
912
+ background: var(--cli-status-error, #f85149);
913
+ }
914
+
915
+ /* ─── Services / Servers dropdown ────────────────────────── */
916
+
917
+ .cli-panel-services-dropdown {
918
+ position: fixed;
919
+ background-color: var(--cli-panel-header-bg, #1f2937);
920
+ border: 1px solid var(--cli-panel-border, #374151);
921
+ border-radius: 8px;
922
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
923
+ z-index: 1100;
924
+ min-width: 260px;
925
+ max-width: 380px;
926
+ overflow: hidden;
927
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
928
+ }
929
+
930
+ .cli-panel-services-dropdown-header {
931
+ padding: 10px 14px 8px;
932
+ font-size: 11px;
933
+ font-weight: 600;
934
+ text-transform: uppercase;
935
+ letter-spacing: 0.05em;
936
+ color: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.5));
937
+ border-bottom: 1px solid var(--cli-panel-border, #374151);
938
+ }
939
+
940
+ .cli-panel-services-dropdown-list {
941
+ max-height: 240px;
942
+ overflow-y: auto;
943
+ scrollbar-width: thin;
944
+ scrollbar-color: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.2)) transparent;
945
+ }
946
+
947
+ .cli-panel-services-dropdown-list::-webkit-scrollbar {
948
+ width: 6px;
949
+ }
950
+
951
+ .cli-panel-services-dropdown-list::-webkit-scrollbar-track {
952
+ background: transparent;
953
+ }
954
+
955
+ .cli-panel-services-dropdown-list::-webkit-scrollbar-thumb {
956
+ background: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.2));
957
+ border-radius: 3px;
958
+ }
959
+
960
+ .cli-panel-services-dropdown-list::-webkit-scrollbar-thumb:hover {
961
+ background: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.35));
962
+ }
963
+
964
+ .cli-panel-services-dropdown-item {
965
+ display: flex;
966
+ align-items: flex-start;
967
+ gap: 10px;
968
+ padding: 10px 14px;
969
+ border-bottom: 1px solid rgba(255, 255, 255, 0.04);
970
+ transition: background-color 0.15s ease;
971
+ }
972
+
973
+ .cli-panel-services-dropdown-item:last-child {
974
+ border-bottom: none;
975
+ }
976
+
977
+ .cli-panel-services-dropdown-item:hover {
978
+ background-color: var(--cli-btn-hover-bg, rgba(129, 140, 248, 0.08));
979
+ }
980
+
981
+ .cli-panel-svc-dot {
982
+ width: 7px;
983
+ height: 7px;
984
+ border-radius: 50%;
985
+ flex-shrink: 0;
986
+ margin-top: 5px;
987
+ }
988
+
989
+ .cli-panel-svc-dot.svc-running {
990
+ background: var(--cli-status-idle, #3fb950);
991
+ }
992
+
993
+ .cli-panel-svc-dot.svc-stopped {
994
+ background: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.3));
995
+ }
996
+
997
+ .cli-panel-svc-info {
998
+ flex: 1;
999
+ min-width: 0;
1000
+ display: flex;
1001
+ flex-direction: column;
1002
+ gap: 2px;
1003
+ }
1004
+
1005
+ .cli-panel-svc-name {
1006
+ font-size: 13px;
1007
+ font-weight: 500;
1008
+ color: var(--cli-panel-text, rgba(255, 255, 255, 0.87));
1009
+ overflow: hidden;
1010
+ text-overflow: ellipsis;
1011
+ white-space: nowrap;
1012
+ }
1013
+
1014
+ .cli-panel-svc-desc {
1015
+ font-size: 11px;
1016
+ color: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.5));
1017
+ overflow: hidden;
1018
+ text-overflow: ellipsis;
1019
+ white-space: nowrap;
1020
+ }
1021
+
1022
+ .cli-panel-svc-status {
1023
+ font-size: 11px;
1024
+ flex-shrink: 0;
1025
+ color: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.5));
1026
+ margin-top: 1px;
1027
+ }
1028
+
1029
+ .cli-panel-srv-meta {
1030
+ display: flex;
1031
+ flex-direction: column;
1032
+ align-items: flex-end;
1033
+ gap: 2px;
1034
+ flex-shrink: 0;
1035
+ }
1036
+
1037
+ .cli-panel-services-dropdown-empty {
1038
+ padding: 16px 14px;
1039
+ font-size: 12px;
1040
+ color: var(--cli-panel-text-secondary, rgba(255, 255, 255, 0.4));
1041
+ text-align: center;
1042
+ }
1043
+
1044
+ /* ─── Glow line ──────────────────────────────────────────── */
1045
+
1046
+ .cli-panel-glow-line {
1047
+ position: absolute;
1048
+ bottom: 0;
1049
+ left: 0;
1050
+ right: 0;
1051
+ height: 2px;
1052
+ background: linear-gradient(90deg, transparent, var(--cli-status-glow, var(--cli-panel-accent, #818cf8)), #a78bfa, var(--cli-status-glow, var(--cli-panel-accent, #818cf8)), transparent);
1053
+ background-size: 200% 100%;
1054
+ opacity: 0.4;
1055
+ animation: cliGlowShift 8s ease-in-out infinite;
1056
+ transition: opacity 0.6s ease;
1057
+ pointer-events: none;
1058
+ }
1059
+
1060
+ .cli-panel-glow-line.glow-active {
1061
+ opacity: 0.8;
1062
+ animation-duration: 3s;
1063
+ }
1064
+
1065
+ /* Glow line for vertical positions */
1066
+ .cli-panel-wrapper[data-position="left"] .cli-panel-glow-line {
1067
+ bottom: auto;
1068
+ top: 0;
1069
+ left: auto;
1070
+ right: 0;
1071
+ width: 2px;
1072
+ height: 100%;
1073
+ background: linear-gradient(180deg, transparent, var(--cli-status-glow, var(--cli-panel-accent, #818cf8)), #a78bfa, var(--cli-status-glow, var(--cli-panel-accent, #818cf8)), transparent);
1074
+ background-size: 100% 200%;
1075
+ }
1076
+
1077
+ .cli-panel-wrapper[data-position="right"] .cli-panel-glow-line {
1078
+ bottom: auto;
1079
+ top: 0;
1080
+ left: 0;
1081
+ right: auto;
1082
+ width: 2px;
1083
+ height: 100%;
1084
+ background: linear-gradient(180deg, transparent, var(--cli-status-glow, var(--cli-panel-accent, #818cf8)), #a78bfa, var(--cli-status-glow, var(--cli-panel-accent, #818cf8)), transparent);
1085
+ background-size: 100% 200%;
1086
+ }
1087
+
1088
+ /* ─── Animations ─────────────────────────────────────────── */
1089
+
1090
+ @keyframes cliStatusPulse {
1091
+ 0%, 100% { opacity: 1; }
1092
+ 50% { opacity: 0.3; }
1093
+ }
1094
+
1095
+ @keyframes cliGlowShift {
1096
+ 0% { background-position: 200% center; }
1097
+ 100% { background-position: -200% center; }
1098
+ }
1099
+
1100
+ /* ─── Accessibility ──────────────────────────────────────── */
1101
+
1102
+ @media (prefers-reduced-motion: reduce) {
1103
+ .cli-panel-glow-line,
1104
+ .cli-panel-status-dot,
1105
+ .cli-panel-tab-dot {
1106
+ animation: none !important;
1107
+ }
1108
+ }
1109
+
1110
+ /* ─── Scrollbar styling — scoped to CLI containers ────────── */
1111
+
1112
+ .cli-panel-wrapper .xterm .xterm-viewport {
1113
+ overscroll-behavior: contain;
1114
+ }
1115
+
1116
+ .cli-panel-wrapper .xterm .xterm-viewport::-webkit-scrollbar {
1117
+ width: 8px;
1118
+ }
1119
+
1120
+ .cli-panel-wrapper .xterm .xterm-viewport::-webkit-scrollbar-thumb {
1121
+ background: #444;
1122
+ border-radius: 4px;
1123
+ }
1124
+
1125
+ .cli-panel-wrapper .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover {
1126
+ background: #666;
1127
+ }
1128
+
812
1129
  /* ─── Global helper ──────────────────────────────────────── */
813
1130
 
814
1131
  body.cli-pane-resizing {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qodalis/cli",
3
- "version": "2.0.0-beta.11",
3
+ "version": "2.0.0-beta.12",
4
4
  "description": "Framework-agnostic CLI engine for @qodalis terminal applications.",
5
5
  "author": "Nicolae Lupei, Qodalis Solutions",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "./assets/*": "./assets/*"
31
31
  },
32
32
  "dependencies": {
33
- "@qodalis/cli-core": "2.0.0-beta.11",
33
+ "@qodalis/cli-core": "2.0.0-beta.12",
34
34
  "@xterm/xterm": "^5.5.0",
35
35
  "@xterm/addon-fit": "^0.10.0",
36
36
  "@xterm/addon-web-links": "^0.11.0",
package/public-api.d.mts CHANGED
@@ -142,7 +142,7 @@ declare const CliBackgroundServiceRegistry_TOKEN = "cli-background-service-regis
142
142
  */
143
143
  declare const CliPackageManagerService_TOKEN = "cli-package-manager-service";
144
144
 
145
- declare const LIBRARY_VERSION = "2.0.0-beta.11";
145
+ declare const LIBRARY_VERSION = "2.0.0-beta.12";
146
146
  declare const API_VERSION = 2;
147
147
 
148
148
  declare class CliAliasCommandProcessor implements ICliCommandProcessor {
@@ -910,6 +910,9 @@ declare class CliCommandExecutionContext implements ICliExecutionContext {
910
910
  translator: ICliTranslationService;
911
911
  reader: ICliInputReader;
912
912
  readonly backgroundServices: ICliBackgroundServiceRegistry;
913
+ setStatusText(text: string): void;
914
+ clearStatusText(): void;
915
+ getStatusText(): string | undefined;
913
916
  get promptLength(): number;
914
917
  set promptLength(value: number);
915
918
  get currentLine(): string;
@@ -928,6 +931,7 @@ declare class CliCommandExecutionContext implements ICliExecutionContext {
928
931
  exitFullScreenMode: () => void;
929
932
  createInterval: (callback: () => void, ms: number) => ICliManagedInterval;
930
933
  createTimeout: (callback: () => void, ms: number) => ICliManagedTimer;
934
+ submitCommand: (command: string) => Promise<void>;
931
935
  constructor(context: ICliExecutionContext, processor: ICliCommandProcessor);
932
936
  }
933
937
 
@@ -1193,6 +1197,24 @@ declare class CliExecutionContext implements ICliExecutionContext, InputModeHost
1193
1197
  readonly completionEngine: CliCompletionEngine;
1194
1198
  promptLength: number;
1195
1199
  readonly reader: ICliInputReader;
1200
+ /**
1201
+ * Result of the most recently executed command.
1202
+ * Updated by the command executor after each command completes.
1203
+ */
1204
+ lastCommandResult?: {
1205
+ command: string;
1206
+ success: boolean;
1207
+ };
1208
+ /**
1209
+ * Whether a command is currently being executed.
1210
+ * Set by the command executor at start/end of executeCommand().
1211
+ */
1212
+ isExecuting: boolean;
1213
+ private _statusText?;
1214
+ readonly statusTextChange$: Subject<string | undefined>;
1215
+ setStatusText(text: string): void;
1216
+ clearStatusText(): void;
1217
+ getStatusText(): string | undefined;
1196
1218
  readonly lineBuffer: CliLineBuffer;
1197
1219
  readonly lineRenderer: CliTerminalLineRenderer;
1198
1220
  readonly commandHistory: CliCommandHistory;
@@ -1218,6 +1240,12 @@ declare class CliExecutionContext implements ICliExecutionContext, InputModeHost
1218
1240
  newLine?: boolean;
1219
1241
  keepCurrentLine?: boolean;
1220
1242
  }): void;
1243
+ /**
1244
+ * Submit and execute a command — shared by interactive Enter key
1245
+ * and programmatic engine.execute(). Adds to history, runs the
1246
+ * command, and shows a new prompt afterwards.
1247
+ */
1248
+ submitCommand(command: string): Promise<void>;
1221
1249
  clearCurrentLine(): void;
1222
1250
  refreshCurrentLine(previousContentLength?: number): void;
1223
1251
  /**
@@ -1349,6 +1377,11 @@ declare class CliTimerManager {
1349
1377
  interface ICliExecutionHost extends ICliExecutionContext {
1350
1378
  contextProcessor?: ICliCommandProcessor;
1351
1379
  abort?(): void;
1380
+ lastCommandResult?: {
1381
+ command: string;
1382
+ success: boolean;
1383
+ };
1384
+ isExecuting?: boolean;
1352
1385
  }
1353
1386
  declare class CliCommandExecutor implements ICliCommandExecutorService {
1354
1387
  protected readonly registry: ICliCommandProcessorRegistry;
@@ -2034,6 +2067,7 @@ declare class CliEngine {
2034
2067
  private resizeScheduled;
2035
2068
  private bootService?;
2036
2069
  private dragDropService?;
2070
+ private _startedAt?;
2037
2071
  constructor(container: HTMLElement, options?: CliEngineOptions | undefined);
2038
2072
  /**
2039
2073
  * Register a CLI module to be loaded on start().
@@ -2084,7 +2118,13 @@ declare class CliEngine {
2084
2118
  */
2085
2119
  getRegistry(): CliCommandProcessorRegistry;
2086
2120
  /**
2087
- * Execute a command programmatically.
2121
+ * Timestamp (ms since epoch) when the engine finished starting.
2122
+ */
2123
+ get startedAt(): number | undefined;
2124
+ /**
2125
+ * Execute a command programmatically, behaving the same as if the user
2126
+ * typed it and pressed Enter: echoes the command, adds it to history,
2127
+ * executes it, and shows a new prompt afterwards.
2088
2128
  */
2089
2129
  execute(command: string): Promise<void>;
2090
2130
  /**
package/public-api.d.ts CHANGED
@@ -142,7 +142,7 @@ declare const CliBackgroundServiceRegistry_TOKEN = "cli-background-service-regis
142
142
  */
143
143
  declare const CliPackageManagerService_TOKEN = "cli-package-manager-service";
144
144
 
145
- declare const LIBRARY_VERSION = "2.0.0-beta.11";
145
+ declare const LIBRARY_VERSION = "2.0.0-beta.12";
146
146
  declare const API_VERSION = 2;
147
147
 
148
148
  declare class CliAliasCommandProcessor implements ICliCommandProcessor {
@@ -910,6 +910,9 @@ declare class CliCommandExecutionContext implements ICliExecutionContext {
910
910
  translator: ICliTranslationService;
911
911
  reader: ICliInputReader;
912
912
  readonly backgroundServices: ICliBackgroundServiceRegistry;
913
+ setStatusText(text: string): void;
914
+ clearStatusText(): void;
915
+ getStatusText(): string | undefined;
913
916
  get promptLength(): number;
914
917
  set promptLength(value: number);
915
918
  get currentLine(): string;
@@ -928,6 +931,7 @@ declare class CliCommandExecutionContext implements ICliExecutionContext {
928
931
  exitFullScreenMode: () => void;
929
932
  createInterval: (callback: () => void, ms: number) => ICliManagedInterval;
930
933
  createTimeout: (callback: () => void, ms: number) => ICliManagedTimer;
934
+ submitCommand: (command: string) => Promise<void>;
931
935
  constructor(context: ICliExecutionContext, processor: ICliCommandProcessor);
932
936
  }
933
937
 
@@ -1193,6 +1197,24 @@ declare class CliExecutionContext implements ICliExecutionContext, InputModeHost
1193
1197
  readonly completionEngine: CliCompletionEngine;
1194
1198
  promptLength: number;
1195
1199
  readonly reader: ICliInputReader;
1200
+ /**
1201
+ * Result of the most recently executed command.
1202
+ * Updated by the command executor after each command completes.
1203
+ */
1204
+ lastCommandResult?: {
1205
+ command: string;
1206
+ success: boolean;
1207
+ };
1208
+ /**
1209
+ * Whether a command is currently being executed.
1210
+ * Set by the command executor at start/end of executeCommand().
1211
+ */
1212
+ isExecuting: boolean;
1213
+ private _statusText?;
1214
+ readonly statusTextChange$: Subject<string | undefined>;
1215
+ setStatusText(text: string): void;
1216
+ clearStatusText(): void;
1217
+ getStatusText(): string | undefined;
1196
1218
  readonly lineBuffer: CliLineBuffer;
1197
1219
  readonly lineRenderer: CliTerminalLineRenderer;
1198
1220
  readonly commandHistory: CliCommandHistory;
@@ -1218,6 +1240,12 @@ declare class CliExecutionContext implements ICliExecutionContext, InputModeHost
1218
1240
  newLine?: boolean;
1219
1241
  keepCurrentLine?: boolean;
1220
1242
  }): void;
1243
+ /**
1244
+ * Submit and execute a command — shared by interactive Enter key
1245
+ * and programmatic engine.execute(). Adds to history, runs the
1246
+ * command, and shows a new prompt afterwards.
1247
+ */
1248
+ submitCommand(command: string): Promise<void>;
1221
1249
  clearCurrentLine(): void;
1222
1250
  refreshCurrentLine(previousContentLength?: number): void;
1223
1251
  /**
@@ -1349,6 +1377,11 @@ declare class CliTimerManager {
1349
1377
  interface ICliExecutionHost extends ICliExecutionContext {
1350
1378
  contextProcessor?: ICliCommandProcessor;
1351
1379
  abort?(): void;
1380
+ lastCommandResult?: {
1381
+ command: string;
1382
+ success: boolean;
1383
+ };
1384
+ isExecuting?: boolean;
1352
1385
  }
1353
1386
  declare class CliCommandExecutor implements ICliCommandExecutorService {
1354
1387
  protected readonly registry: ICliCommandProcessorRegistry;
@@ -2034,6 +2067,7 @@ declare class CliEngine {
2034
2067
  private resizeScheduled;
2035
2068
  private bootService?;
2036
2069
  private dragDropService?;
2070
+ private _startedAt?;
2037
2071
  constructor(container: HTMLElement, options?: CliEngineOptions | undefined);
2038
2072
  /**
2039
2073
  * Register a CLI module to be loaded on start().
@@ -2084,7 +2118,13 @@ declare class CliEngine {
2084
2118
  */
2085
2119
  getRegistry(): CliCommandProcessorRegistry;
2086
2120
  /**
2087
- * Execute a command programmatically.
2121
+ * Timestamp (ms since epoch) when the engine finished starting.
2122
+ */
2123
+ get startedAt(): number | undefined;
2124
+ /**
2125
+ * Execute a command programmatically, behaving the same as if the user
2126
+ * typed it and pressed Enter: echoes the command, adds it to history,
2127
+ * executes it, and shows a new prompt afterwards.
2088
2128
  */
2089
2129
  execute(command: string): Promise<void>;
2090
2130
  /**