@qodalis/cli-core 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/public-api.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ITerminalOptions, ITerminalInitOnlyOptions, Terminal, ITheme } from '@xterm/xterm';
2
- import { Subject, Observable, Subscription } from 'rxjs';
2
+ import { Observable, Subscription, Subject } from 'rxjs';
3
3
 
4
4
  type CliProcessCommand = {
5
5
  /**
@@ -170,559 +170,428 @@ declare enum CliIcon {
170
170
  Gift = "\uD83C\uDF81"
171
171
  }
172
172
 
173
- /**
174
- * Configuration for a remote CLI server
175
- */
176
- type CliServerConfig = {
177
- /** Unique identifier, used for namespacing commands */
178
- name: string;
179
- /** Base URL of the server, e.g. "https://api.example.com" */
180
- url: string;
181
- /** Whether this server is enabled. @default true */
182
- enabled?: boolean;
183
- /** Custom headers sent with every request (e.g. auth tokens) */
184
- headers?: Record<string, string>;
185
- /** Request timeout in milliseconds. @default 30000 */
186
- timeout?: number;
187
- };
188
- /**
189
- * A single output item in a server response
190
- */
191
- type CliServerOutput = {
192
- type: 'text';
193
- value: string;
194
- style?: 'success' | 'error' | 'info' | 'warning';
195
- } | {
196
- type: 'table';
197
- headers: string[];
198
- rows: string[][];
199
- } | {
200
- type: 'list';
201
- items: string[];
202
- ordered?: boolean;
203
- } | {
204
- type: 'json';
205
- value: any;
206
- } | {
207
- type: 'key-value';
208
- entries: {
209
- key: string;
210
- value: string;
211
- }[];
212
- };
213
- /**
214
- * Structured response from a server command execution
215
- */
216
- type CliServerResponse = {
217
- exitCode: number;
218
- outputs: CliServerOutput[];
219
- };
220
- /**
221
- * Metadata about a remote command processor, returned by GET /api/qcli/commands
222
- */
223
- type CliServerCommandDescriptor = {
224
- command: string;
225
- description?: string;
226
- version?: string;
227
- parameters?: {
228
- name: string;
229
- aliases?: string[];
230
- description: string;
231
- required: boolean;
232
- type: string;
233
- defaultValue?: any;
234
- }[];
235
- processors?: CliServerCommandDescriptor[];
236
- };
237
- /**
238
- * Server capabilities returned by GET /api/qcli/capabilities
239
- */
240
- type CliServerCapabilities = {
241
- /** Whether this server supports remote shell access */
242
- shell: boolean;
243
- /** Server operating system (e.g. "linux", "win32", "darwin") */
244
- os?: string;
245
- /** Path to the shell binary on the server */
246
- shellPath?: string;
247
- /** Server version string */
248
- version?: string;
249
- /** Whether this server supports SSE streaming execution */
250
- streaming?: boolean;
251
- };
252
-
253
- /**
254
- * Represents a package source for the CLI package manager
255
- */
256
- interface CliPackageSource {
173
+ interface CliTableOptions {
174
+ /** Expand columns to fill the full terminal width. Default: false */
175
+ fullWidth?: boolean;
176
+ }
177
+ interface ICliTerminalWriter {
257
178
  /**
258
- * The name of the source, e.g. 'local', 'unpkg', 'jsdelivr'
179
+ * Write text to the terminal
180
+ * @param text The text to write
259
181
  */
260
- name: string;
182
+ write(text: string): void;
261
183
  /**
262
- * The base URL for fetching package files, e.g. 'http://localhost:3000/'
184
+ * Write text to the terminal followed by a newline
185
+ * @param text The text to write
263
186
  */
264
- url: string;
187
+ writeln(text?: string): void;
265
188
  /**
266
- * The kind of source.
267
- * - 'registry': npm-compatible registry with search API (e.g. npmjs.org, Verdaccio)
268
- * - 'file': static file server, packages are discovered by probing known paths
269
- * @default 'file'
189
+ * Write a success message to the terminal
190
+ * @param message The message to write
270
191
  */
271
- kind?: 'registry' | 'file';
272
- }
273
- /**
274
- * Represents a log level for the CLI
275
- */
276
- declare enum CliLogLevel {
277
- None = 0,
278
- DEBUG = 1,
279
- LOG = 2,
280
- INFO = 3,
281
- WARN = 4,
282
- ERROR = 5
283
- }
284
- /**
285
- * Options for the CLI
286
- */
287
- type CliOptions = Record<string, any> & {
192
+ writeSuccess(message: string): void;
288
193
  /**
289
- * Custom terminal options
194
+ * Write an info message to the terminal
195
+ * @param message The message to write
290
196
  */
291
- terminalOptions?: ITerminalOptions & ITerminalInitOnlyOptions;
197
+ writeInfo(message: string): void;
292
198
  /**
293
- * The minimum log level to display
199
+ * Write an error message to the terminal
200
+ * @param message The message to write
294
201
  */
295
- logLevel?: CliLogLevel;
202
+ writeError(message: string): void;
296
203
  /**
297
- * Custom package sources for the package manager.
298
- * Built-in sources (unpkg, jsdelivr) are always available.
204
+ * Write a warning message to the terminal
205
+ * @param message The message to write
299
206
  */
300
- packageSources?: {
301
- /**
302
- * Name of the primary source. Defaults to 'unpkg'.
303
- */
304
- primary?: string;
305
- /**
306
- * Additional custom sources
307
- */
308
- sources?: CliPackageSource[];
309
- };
207
+ writeWarning(message: string): void;
310
208
  /**
311
- * Remote CLI servers to connect to.
312
- * Commands from each server are discovered and registered as proxy processors.
209
+ * Wrap text in the specified foreground color.
210
+ * @param text The text to wrap
211
+ * @param color The foreground color to apply
212
+ * @returns The text wrapped in ANSI color codes
313
213
  */
314
- servers?: CliServerConfig[];
214
+ wrapInColor(text: string, color: CliForegroundColor): string;
315
215
  /**
316
- * Whether the `eval` / `js` / `calc` command is enabled.
317
- * Disabled by default because it runs arbitrary JavaScript via `eval()`
318
- * in the host page context — a security risk in multi-tenant or
319
- * user-facing deployments.
320
- * @default false
216
+ * Wrap text in the specified background color.
217
+ * @param text The text to wrap
218
+ * @param color The background color to apply
219
+ * @returns The text wrapped in ANSI background color codes
321
220
  */
322
- allowEval?: boolean;
323
- };
324
- /**
325
- * Represents a package that can be installed
326
- */
327
- interface Package {
221
+ wrapInBackgroundColor(text: string, color: CliBackgroundColor): string;
328
222
  /**
329
- * The name of the package
223
+ * Write a JSON object to the terminal
224
+ * @param json The JSON object to write
330
225
  */
331
- name: string;
226
+ writeJson(json: any): void;
332
227
  /**
333
- * The global name used to access the package
228
+ * Write content to a file (triggers a browser download)
229
+ * @param fileName The name of the file to download
230
+ * @param content The content to write to the file
334
231
  */
335
- globalName?: string;
232
+ writeToFile(fileName: string, content: string): void;
336
233
  /**
337
- * The version of the package
234
+ * Write an object array as a table to the terminal
235
+ * @param objects The objects to write to the table
338
236
  */
339
- version: string;
237
+ writeObjectsAsTable(objects: any[]): void;
340
238
  /**
341
- * The unpkg url to the package
239
+ * Write a table to the terminal
240
+ * @param headers The headers of the table
241
+ * @param rows The rows of the table
242
+ * @param options Optional table rendering options
342
243
  */
343
- url: string;
244
+ writeTable(headers: string[], rows: string[][], options?: CliTableOptions): void;
344
245
  /**
345
- * The dependencies for the module
246
+ * Write a divider to the terminal
247
+ * @param options Optional: color, length, character
346
248
  */
347
- dependencies?: Package[];
348
- }
349
- /**
350
- * Represents command processor metadata
351
- */
352
- type CliProcessorMetadata = Record<string, any> & {
249
+ writeDivider(options?: {
250
+ color?: CliForegroundColor;
251
+ length?: number;
252
+ char?: string;
253
+ }): void;
353
254
  /**
354
- * If true, the processor is sealed and cannot be replaced or removed.
355
- * Sealed processors can still be extended (wrapped) by processors with `extendsProcessor = true`.
255
+ * Write a list of items to the terminal with bullet, numbered, or custom prefix.
256
+ * @param items The list items to display
257
+ * @param options Optional: ordered (numbered), prefix (custom marker), color
356
258
  */
357
- sealed?: boolean;
259
+ writeList(items: string[], options?: {
260
+ ordered?: boolean;
261
+ prefix?: string;
262
+ color?: CliForegroundColor;
263
+ }): void;
358
264
  /**
359
- * If true, the processor requires the server to be running
265
+ * Write aligned key-value pairs to the terminal.
266
+ * @param entries Key-value pairs as a Record or array of tuples
267
+ * @param options Optional: separator string, key color
360
268
  */
361
- requireServer?: boolean;
269
+ writeKeyValue(entries: Record<string, string> | [string, string][], options?: {
270
+ separator?: string;
271
+ keyColor?: CliForegroundColor;
272
+ }): void;
362
273
  /**
363
- * The module the processor belongs to
274
+ * Write items in a multi-column layout.
275
+ * @param items The items to arrange in columns
276
+ * @param options Optional: number of columns, padding between columns
364
277
  */
365
- module?: string;
278
+ writeColumns(items: string[], options?: {
279
+ columns?: number;
280
+ padding?: number;
281
+ }): void;
366
282
  /**
367
- * An icon to display for the processor
283
+ * Write a clickable hyperlink using OSC 8 escape sequences.
284
+ * In terminals that support OSC 8, the text is clickable. In others,
285
+ * it falls back to displaying "text (url)".
286
+ * @param text The visible link text
287
+ * @param url The URL to link to
368
288
  */
369
- icon?: CliIcon | string;
289
+ writeLink(text: string, url: string): void;
370
290
  /**
371
- * The minimum required version of @qodalis/cli-core for this processor.
372
- * If the installed core version is lower, the processor will be skipped during boot.
291
+ * Write text inside a bordered box.
292
+ * Useful for callouts, notices, and highlighted information.
293
+ * @param content The content lines to display inside the box
294
+ * @param options Optional: title, border color, padding
373
295
  */
374
- requiredCoreVersion?: string;
296
+ writeBox(content: string | string[], options?: {
297
+ title?: string;
298
+ borderColor?: CliForegroundColor;
299
+ padding?: number;
300
+ }): void;
375
301
  /**
376
- * The minimum required version of @qodalis/cli for this processor.
377
- * If the installed CLI version is lower, the processor will be skipped during boot.
378
- */
379
- requiredCliVersion?: string;
380
- /**
381
- * If true, the processor is hidden from the help command listing.
382
- * The command still works when typed directly and `help <command>` still shows its details.
302
+ * Write text with a specified indentation level.
303
+ * Each level adds 2 spaces of indentation.
304
+ * @param text The text to write
305
+ * @param level The indentation level (default: 1)
383
306
  */
384
- hidden?: boolean;
385
- };
307
+ writeIndented(text: string, level?: number): void;
308
+ }
309
+
386
310
  /**
387
- * Represents a state configuration for the CLI processor
311
+ * Represents a clipboard for the CLI
388
312
  */
389
- type CliStateConfiguration = {
313
+ interface ICliClipboard {
390
314
  /**
391
- * The initial state for the processor
315
+ * Write text to the clipboard
316
+ * @param text The text to write to the clipboard
317
+ * @returns void
392
318
  */
393
- initialState: Record<string, any>;
319
+ write: (text: string) => Promise<void>;
394
320
  /**
395
- * The store identifier for the processor, if any
396
- * @remarks If the store identifier is not set, the processor command name is used
321
+ * Read text from the clipboard
322
+ * @returns The text read from the clipboard
397
323
  */
398
- storeName?: string;
399
- };
400
- type CliState = Record<string, any>;
401
- /**
402
- * Position of the CLI panel relative to the viewport edge.
403
- * - `'bottom'` — anchored to the bottom (default)
404
- * - `'top'` — anchored to the top
405
- * - `'left'` — anchored to the left (vertical layout)
406
- * - `'right'` — anchored to the right (vertical layout)
407
- */
408
- type CliPanelPosition = 'bottom' | 'top' | 'left' | 'right';
324
+ read: () => Promise<string>;
325
+ }
326
+
409
327
  /**
410
- * Alignment of the hidden-mode tab along its viewport edge.
411
- * - `'start'` — left for horizontal panels, top for vertical panels
412
- * - `'center'` — centered along the edge (default)
413
- * - `'end'` — right for horizontal panels, bottom for vertical panels
328
+ * Describes a global parameter (e.g. --help, --version) together with
329
+ * the handler that executes when the parameter is present.
330
+ *
331
+ * Global parameters are checked for every command before the command
332
+ * processor's own `processCommand` runs. If the handler returns `true`,
333
+ * command execution is halted (the parameter "consumed" the invocation).
414
334
  */
415
- type CliPanelHideAlignment = 'start' | 'center' | 'end';
335
+ interface ICliGlobalParameterHandler {
336
+ /**
337
+ * The parameter descriptor shown in help output and used for tab-completion.
338
+ */
339
+ parameter: ICliCommandParameterDescriptor;
340
+ /**
341
+ * Execution priority — lower values run first.
342
+ * @default 0
343
+ */
344
+ priority?: number;
345
+ /**
346
+ * Evaluate and optionally handle the parameter.
347
+ * @returns `true` to halt command execution, `false` to continue.
348
+ */
349
+ handle(args: Record<string, any>, processor: ICliCommandProcessor, command: CliProcessCommand, context: ICliExecutionContext): boolean | Promise<boolean>;
350
+ }
351
+
416
352
  /**
417
- * Configuration for the CLI panel component.
353
+ * Represents a service that executes commands
418
354
  */
419
- interface CliPanelConfig {
355
+ interface ICliCommandExecutorService {
420
356
  /**
421
- * Whether the CLI should be collapsed by default.
422
- * @default true
357
+ * Display the help output for a command, including its description,
358
+ * sub-commands, and parameters.
359
+ * @param command The parsed command to show help for
360
+ * @param context The execution context
423
361
  */
424
- isCollapsed?: boolean;
362
+ showHelp(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
425
363
  /**
426
- * Whether the panel starts hidden (showing only the small tab/arrow).
427
- * @default false
364
+ * Execute a command
365
+ * @param command The command to execute
366
+ * @param context The context in which the command is executed
428
367
  */
429
- isHidden?: boolean;
368
+ executeCommand(command: string, context: ICliExecutionContext): Promise<void>;
430
369
  /**
431
- * Position of the panel relative to the viewport.
432
- * @default 'bottom'
370
+ * Register a global parameter handler.
371
+ * Global parameters (e.g. --help, --version) are evaluated for every
372
+ * command before the processor's own processCommand runs.
373
+ * @param handler The global parameter handler to register
433
374
  */
434
- position?: CliPanelPosition;
375
+ registerGlobalParameter(handler: ICliGlobalParameterHandler): void;
435
376
  /**
436
- * Whether the close button is shown.
437
- * @default true
377
+ * Returns the descriptors of all registered global parameters.
378
+ * Used by help output and tab-completion.
438
379
  */
439
- closable?: boolean;
380
+ getGlobalParameters(): ICliCommandParameterDescriptor[];
381
+ }
382
+
383
+ /**
384
+ * Represents a registry for command processors
385
+ */
386
+ interface ICliCommandProcessorRegistry {
440
387
  /**
441
- * Whether the panel can be resized by dragging.
442
- * @default true
388
+ * The processors registered with the registry
443
389
  */
444
- resizable?: boolean;
390
+ readonly processors: ICliCommandProcessor[];
445
391
  /**
446
- * Whether the hide button is shown. When hidden, the panel collapses
447
- * to a small tab at the viewport edge.
448
- * @default true
392
+ * Find a processor for a command
393
+ * @param mainCommand
394
+ * @param chainCommands
449
395
  */
450
- hideable?: boolean;
396
+ findProcessor(mainCommand: string, chainCommands: string[]): ICliCommandProcessor | undefined;
451
397
  /**
452
- * Alignment of the hide tab along the panel's viewport edge.
453
- * For bottom/top: 'start' = left, 'center', 'end' = right.
454
- * For left/right: 'start' = top, 'center', 'end' = bottom.
455
- * @default 'center'
398
+ * Recursively searches for a processor matching the given command.
399
+ * @param mainCommand The main command name.
400
+ * @param chainCommands The remaining chain commands (if any).
401
+ * @param processors The list of available processors.
402
+ * @returns The matching processor or undefined if not found.
456
403
  */
457
- hideAlignment?: CliPanelHideAlignment;
404
+ findProcessorInCollection(mainCommand: string, chainCommands: string[], processors: ICliCommandProcessor[]): ICliCommandProcessor | undefined;
458
405
  /**
459
- * When true, the panel's chrome (header, border, background) automatically
460
- * syncs its colors with the active terminal theme. CSS custom properties
461
- * are derived from the xterm theme and applied as inline styles.
462
- * @default false
406
+ * Get the root processor for a child processor
407
+ * @param child The child processor
463
408
  */
464
- syncTheme?: boolean;
465
- }
466
-
467
- type MultiServices = {
409
+ getRootProcessor(child: ICliCommandChildProcessor): ICliCommandProcessor;
468
410
  /**
469
- * When true, injector returns an array of instances. This is useful to allow multiple
470
- * providers spread across many files to provide configuration information to a common token.
411
+ * Register a processor
412
+ * @param processor
471
413
  */
472
- multi?: boolean;
473
- };
474
- type CliValueProvider = MultiServices & {
475
- useValue: any;
476
- };
477
- type CliTypeProvider = MultiServices & {
478
- useClass: any;
479
- };
480
- type CliFactoryProvider = MultiServices & {
481
- useFactory: Function;
482
- };
483
- type CliProvider = {
484
- provide: any;
485
- } & (CliValueProvider | CliTypeProvider | CliFactoryProvider) & Record<string, any>;
486
-
414
+ registerProcessor(processor: ICliCommandProcessor): void;
415
+ /**
416
+ * Unregister a processor
417
+ * @param processor
418
+ */
419
+ unregisterProcessor(processor: ICliCommandProcessor): void;
420
+ }
487
421
  /**
488
- * Represents a user in the CLI
422
+ * Represents a tracked CLI process entry
489
423
  */
490
- interface ICliUser {
491
- /** Unique user identifier */
492
- id: string;
493
- /** Login name (unique) */
424
+ interface ICliProcessEntry {
425
+ pid: number;
426
+ /** Display name (service name for bg services, command text for commands) */
494
427
  name: string;
495
- /** Email address (unique) */
496
- email: string;
497
- /** Group IDs this user belongs to */
498
- groups: string[];
499
- /** Virtual home directory path, e.g. /home/root */
500
- homeDir?: string;
501
- /** Account creation timestamp */
502
- createdAt: number;
503
- /** Last modification timestamp */
504
- updatedAt: number;
505
- /** Whether the account is locked */
506
- disabled?: boolean;
428
+ /** Process type */
429
+ type: 'command' | 'daemon' | 'job' | 'service';
430
+ command: string;
431
+ startTime: number;
432
+ status: 'running' | 'completed' | 'failed' | 'killed';
433
+ exitCode?: number;
507
434
  }
508
- /**
509
- * Represents user credentials (shadow pattern — stored separately from ICliUser)
510
- */
511
- interface ICliUserCredentials {
512
- /** The user ID this credential belongs to */
513
- userId: string;
514
- /** SHA-256 hash of salt + password */
515
- passwordHash: string;
516
- /** Random salt for this user */
517
- salt: string;
518
- /** Timestamp of last password change */
519
- lastChanged: number;
435
+ /** Options for registering a process */
436
+ interface ICliProcessRegisterOptions {
437
+ /** Display name (defaults to command) */
438
+ name?: string;
439
+ /** Process type (defaults to 'command') */
440
+ type?: 'command' | 'daemon' | 'job' | 'service';
441
+ /** Custom kill handler (e.g. for background services) */
442
+ onKill?: () => Promise<void> | void;
520
443
  }
521
444
  /**
522
- * Represents a group in the CLI
445
+ * Registry for tracking CLI processes
523
446
  */
524
- interface ICliGroup {
525
- /** Unique group identifier */
526
- id: string;
527
- /** Group name (unique) */
528
- name: string;
529
- /** Optional group description */
530
- description?: string;
531
- /** Group creation timestamp */
532
- createdAt: number;
447
+ interface ICliProcessRegistry {
448
+ /** Register a new process, returns assigned PID */
449
+ register(command: string, options?: ICliProcessRegisterOptions): {
450
+ pid: number;
451
+ abortController: AbortController;
452
+ };
453
+ /** Mark process as completed */
454
+ complete(pid: number, exitCode: number): void;
455
+ /** Mark process as failed */
456
+ fail(pid: number): void;
457
+ /** Kill a process by PID */
458
+ kill(pid: number): boolean;
459
+ /** List all processes (running + recent completed) */
460
+ list(): ICliProcessEntry[];
461
+ /** Get the current foreground process PID */
462
+ readonly currentPid: number | undefined;
533
463
  }
534
- /**
535
- * Represents an active user session
536
- */
537
- interface ICliUserSession {
538
- /** The user associated with this session */
539
- user: ICliUser;
540
- /** Pre-computed display name for the prompt (set by users module) */
541
- displayName?: string;
542
- /** Timestamp when the session started */
543
- loginTime: number;
544
- /** Timestamp of last activity */
545
- lastActivity: number;
546
- /** Extensible data (tokens, metadata, etc.) */
547
- data?: Record<string, any>;
548
- }
549
- /** Fields required to create a new user */
550
- type CliAddUser = Omit<ICliUser, 'id' | 'createdAt' | 'updatedAt'>;
551
- /** Fields that can be updated on a user */
552
- type CliUpdateUser = Partial<Omit<ICliUser, 'id' | 'createdAt'>>;
553
-
554
- /** Ownership metadata attached to files, directories, or other resources */
555
- interface ICliOwnership {
556
- /** User ID of the owner */
557
- uid: string;
558
- /** Primary group name */
559
- gid: string;
560
- }
561
- /** Default file permissions: rw-r--r-- (644) */
562
- declare const DEFAULT_FILE_PERMISSIONS = "rw-r--r--";
563
- /** Default directory permissions: rwxr-xr-x (755) */
564
- declare const DEFAULT_DIR_PERMISSIONS = "rwxr-xr-x";
565
-
566
- declare const enums: {
567
- CliForegroundColor: typeof CliForegroundColor;
568
- CliBackgroundColor: typeof CliBackgroundColor;
569
- CliIcon: typeof CliIcon;
570
- CliLogLevel: typeof CliLogLevel;
571
- };
572
464
 
573
- interface CliTableOptions {
574
- /** Expand columns to fill the full terminal width. Default: false */
575
- fullWidth?: boolean;
576
- }
577
- interface ICliTerminalWriter {
465
+ interface ICliExecutionProcess {
578
466
  /**
579
- * Write text to the terminal
580
- * @param text The text to write
467
+ * Indicates if the process has exited
581
468
  */
582
- write(text: string): void;
469
+ exited?: boolean;
583
470
  /**
584
- * Write text to the terminal followed by a newline
585
- * @param text The text to write
471
+ * The exit code of the process
586
472
  */
587
- writeln(text?: string): void;
473
+ exitCode?: number;
588
474
  /**
589
- * Write a success message to the terminal
590
- * @param message The message to write
475
+ * Indicates if the process is running
591
476
  */
592
- writeSuccess(message: string): void;
477
+ running: boolean;
593
478
  /**
594
- * Write an info message to the terminal
595
- * @param message The message to write
479
+ * The data of the process
596
480
  */
597
- writeInfo(message: string): void;
481
+ data: any | undefined;
598
482
  /**
599
- * Write an error message to the terminal
600
- * @param message The message to write
483
+ * Exit the process
484
+ * @param code The exit code
485
+ * @returns void
601
486
  */
602
- writeError(message: string): void;
487
+ exit: (
603
488
  /**
604
- * Write a warning message to the terminal
605
- * @param message The message to write
489
+ * The exit code
606
490
  */
607
- writeWarning(message: string): void;
491
+ code?: number,
608
492
  /**
609
- * Wrap text in the specified foreground color.
610
- * @param text The text to wrap
611
- * @param color The foreground color to apply
612
- * @returns The text wrapped in ANSI color codes
493
+ * Options for exiting the process
613
494
  */
614
- wrapInColor(text: string, color: CliForegroundColor): string;
495
+ options?: {
496
+ /**
497
+ * Indicates if the exit should be silent, i.e. not throw an error
498
+ */
499
+ silent?: boolean;
500
+ }) => void;
615
501
  /**
616
- * Wrap text in the specified background color.
617
- * @param text The text to wrap
618
- * @param color The background color to apply
619
- * @returns The text wrapped in ANSI background color codes
502
+ * Output data from the process
503
+ * @param data The data to output
620
504
  */
621
- wrapInBackgroundColor(text: string, color: CliBackgroundColor): string;
505
+ output(data: any): void;
506
+ }
507
+
508
+ /**
509
+ * Represents a key-value store for the CLI
510
+ */
511
+ interface ICliKeyValueStore {
622
512
  /**
623
- * Write a JSON object to the terminal
624
- * @param json The JSON object to write
513
+ * Retrieves a value by key.
514
+ * @param key - The key to retrieve the value for.
515
+ * @returns A promise resolving to the value or undefined if not found.
625
516
  */
626
- writeJson(json: any): void;
517
+ get<T = any>(key: string): Promise<T | undefined>;
627
518
  /**
628
- * Write content to a file (triggers a browser download)
629
- * @param fileName The name of the file to download
630
- * @param content The content to write to the file
519
+ * Sets a key-value pair in the store.
520
+ * @param key - The key to set.
521
+ * @param value - The value to store.
522
+ * @returns A promise resolving when the value is stored.
631
523
  */
632
- writeToFile(fileName: string, content: string): void;
524
+ set(key: string, value: any): Promise<void>;
633
525
  /**
634
- * Write an object array as a table to the terminal
635
- * @param objects The objects to write to the table
526
+ * Removes a key-value pair by key.
527
+ * @param key - The key to remove.
528
+ * @returns A promise resolving when the key is removed.
636
529
  */
637
- writeObjectsAsTable(objects: any[]): void;
530
+ remove(key: string): Promise<void>;
638
531
  /**
639
- * Write a table to the terminal
640
- * @param headers The headers of the table
641
- * @param rows The rows of the table
642
- * @param options Optional table rendering options
532
+ * Clears all key-value pairs from the store.
533
+ * @returns A promise resolving when the store is cleared.
643
534
  */
644
- writeTable(headers: string[], rows: string[][], options?: CliTableOptions): void;
535
+ clear(): Promise<void>;
536
+ }
537
+ /**
538
+ * Reactive state store scoped to a command processor or module.
539
+ *
540
+ * State is a plain object (`Record<string, any>`). Updates are shallow-merged
541
+ * (top-level keys are replaced, nested objects are not deep-merged).
542
+ * `getState()` returns a snapshot — mutating the returned object has no effect;
543
+ * always use `updateState()` to change state.
544
+ */
545
+ interface ICliStateStore {
645
546
  /**
646
- * Write a divider to the terminal
647
- * @param options Optional: color, length, character
547
+ * Get a snapshot of the current state.
548
+ * @returns A shallow copy of the state object
648
549
  */
649
- writeDivider(options?: {
650
- color?: CliForegroundColor;
651
- length?: number;
652
- char?: string;
653
- }): void;
550
+ getState<T extends CliState = CliState>(): T;
654
551
  /**
655
- * Write a list of items to the terminal with bullet, numbered, or custom prefix.
656
- * @param items The list items to display
657
- * @param options Optional: ordered (numbered), prefix (custom marker), color
552
+ * Shallow-merge new values into the current state.
553
+ * Only the provided keys are updated; other keys are preserved.
554
+ * Triggers subscribers and persists if a storage backend is configured.
555
+ * @param newState Partial state to merge with the current state
658
556
  */
659
- writeList(items: string[], options?: {
660
- ordered?: boolean;
661
- prefix?: string;
662
- color?: CliForegroundColor;
663
- }): void;
557
+ updateState(newState: Partial<CliState>): void;
664
558
  /**
665
- * Write aligned key-value pairs to the terminal.
666
- * @param entries Key-value pairs as a Record or array of tuples
667
- * @param options Optional: separator string, key color
559
+ * Select a specific property or computed value from the state.
560
+ * @param selector A function to project a slice of the state.
561
+ * @returns Observable of the selected value.
668
562
  */
669
- writeKeyValue(entries: Record<string, string> | [string, string][], options?: {
670
- separator?: string;
671
- keyColor?: CliForegroundColor;
672
- }): void;
563
+ select<K>(selector: (state: CliState) => K): Observable<K>;
673
564
  /**
674
- * Write items in a multi-column layout.
675
- * @param items The items to arrange in columns
676
- * @param options Optional: number of columns, padding between columns
565
+ * Subscribe to state changes.
566
+ * @param callback Callback function to handle state changes.
567
+ * @returns Subscription object to manage the subscription.
677
568
  */
678
- writeColumns(items: string[], options?: {
679
- columns?: number;
680
- padding?: number;
681
- }): void;
569
+ subscribe(callback: (state: CliState) => void): Subscription;
682
570
  /**
683
- * Write a clickable hyperlink using OSC 8 escape sequences.
684
- * In terminals that support OSC 8, the text is clickable. In others,
685
- * it falls back to displaying "text (url)".
686
- * @param text The visible link text
687
- * @param url The URL to link to
571
+ * Reset the state to its initial value.
688
572
  */
689
- writeLink(text: string, url: string): void;
573
+ reset(): void;
690
574
  /**
691
- * Write text inside a bordered box.
692
- * Useful for callouts, notices, and highlighted information.
693
- * @param content The content lines to display inside the box
694
- * @param options Optional: title, border color, padding
575
+ * Persist the state to storage.
695
576
  */
696
- writeBox(content: string | string[], options?: {
697
- title?: string;
698
- borderColor?: CliForegroundColor;
699
- padding?: number;
700
- }): void;
577
+ persist(): Promise<void>;
701
578
  /**
702
- * Write text with a specified indentation level.
703
- * Each level adds 2 spaces of indentation.
704
- * @param text The text to write
705
- * @param level The indentation level (default: 1)
579
+ * Initialize the state from storage.
706
580
  */
707
- writeIndented(text: string, level?: number): void;
581
+ initialize(): Promise<void>;
708
582
  }
709
583
 
710
- /**
711
- * Represents a clipboard for the CLI
712
- */
713
- interface ICliClipboard {
714
- /**
715
- * Write text to the clipboard
716
- * @param text The text to write to the clipboard
717
- * @returns void
718
- */
719
- write: (text: string) => Promise<void>;
720
- /**
721
- * Read text from the clipboard
722
- * @returns The text read from the clipboard
723
- */
724
- read: () => Promise<string>;
584
+ /** Ownership metadata attached to files, directories, or other resources */
585
+ interface ICliOwnership {
586
+ /** User ID of the owner */
587
+ uid: string;
588
+ /** Primary group name */
589
+ gid: string;
725
590
  }
591
+ /** Default file permissions: rw-r--r-- (644) */
592
+ declare const DEFAULT_FILE_PERMISSIONS = "rw-r--r--";
593
+ /** Default directory permissions: rwxr-xr-x (755) */
594
+ declare const DEFAULT_DIR_PERMISSIONS = "rwxr-xr-x";
726
595
 
727
596
  /**
728
597
  * Token for the CLI user session service.
@@ -764,6 +633,31 @@ declare const ICliPermissionService_TOKEN = "cli-permission-service";
764
633
  * Token for the file picker provider.
765
634
  */
766
635
  declare const ICliFilePickerProvider_TOKEN = "cli-file-picker-provider";
636
+ /**
637
+ * Token for the HTTP client service.
638
+ */
639
+ declare const ICliHttpClient_TOKEN = "cli-http-client";
640
+
641
+ /**
642
+ * Abstract permission service for checking rwx permissions on resources.
643
+ * The default implementation lives in @qodalis/cli-users; consumers can
644
+ * replace it via the DI container.
645
+ */
646
+ interface ICliPermissionService {
647
+ /**
648
+ * Check whether a user may perform an action on a resource.
649
+ * @param user The acting user.
650
+ * @param action The requested operation.
651
+ * @param ownership Owner/group of the resource.
652
+ * @param permissions Permission string (e.g. "rwxr-xr-x").
653
+ * @returns true if allowed.
654
+ */
655
+ check(user: ICliUser, action: 'read' | 'write' | 'execute', ownership: ICliOwnership, permissions: string): boolean;
656
+ /** Parse octal (e.g. "755") to a permission string (e.g. "rwxr-xr-x"). */
657
+ parseOctal(octal: string): string;
658
+ /** Convert a permission string (e.g. "rwxr-xr-x") to octal (e.g. "755"). */
659
+ toOctal(permissions: string): string;
660
+ }
767
661
 
768
662
  /**
769
663
  * Options for readFile file picker.
@@ -989,10 +883,210 @@ interface ICliInputReader {
989
883
  }
990
884
 
991
885
  /**
992
- * Background service lifecycle type.
993
- * - `'daemon'` — Long-running service whose `onStart` blocks until the abort signal
994
- * fires. Suitable for event loops, polling, or WebSocket connections. Can be
995
- * stopped and restarted.
886
+ * Context passed to completion providers describing the current input state.
887
+ */
888
+ interface ICliCompletionContext {
889
+ /** Full current line text */
890
+ input: string;
891
+ /** Cursor position in the line */
892
+ cursor: number;
893
+ /** The token (word) being completed at the cursor position */
894
+ token: string;
895
+ /** Start index of the token in the input string */
896
+ tokenStart: number;
897
+ /** Index of the token among all tokens (0 = command, 1+ = arguments) */
898
+ tokenIndex: number;
899
+ /** All tokens parsed from the input */
900
+ tokens: string[];
901
+ }
902
+ /**
903
+ * Provides tab-completion candidates for CLI input.
904
+ * Plugins can register providers to extend completion (e.g. file paths, custom values).
905
+ */
906
+ interface ICliCompletionProvider {
907
+ /**
908
+ * Priority order. Lower values are checked first.
909
+ * Built-in defaults: 100 (commands), 200 (parameters).
910
+ * Plugins should use lower values (e.g. 50) to take precedence for specific commands.
911
+ */
912
+ priority: number;
913
+ /**
914
+ * Return completion candidates for the current input context.
915
+ * Return an empty array if this provider does not apply.
916
+ */
917
+ getCompletions(context: ICliCompletionContext): string[] | Promise<string[]>;
918
+ }
919
+
920
+ interface ICliProgressBar {
921
+ /**
922
+ * Indicates if the progress bar is running
923
+ */
924
+ isRunning: boolean;
925
+ /**
926
+ * Show the progress bar
927
+ */
928
+ show: (text?: string) => void;
929
+ /**
930
+ * Hide the progress bar
931
+ */
932
+ hide: () => void;
933
+ }
934
+ /**
935
+ * Represents a spinner for the CLI
936
+ */
937
+ interface ICliSpinner extends ICliProgressBar {
938
+ /**
939
+ * Set the text of the spinner
940
+ * @param text The text to set
941
+ */
942
+ setText: (text: string) => void;
943
+ }
944
+ type CliPercentageProgressBarUpdateValueOptions = {
945
+ /**
946
+ * The type of update to perform
947
+ * @default 'replace'
948
+ */
949
+ type?: 'replace' | 'increment';
950
+ };
951
+ /**
952
+ * Represents a progress bar for the CLI
953
+ */
954
+ interface ICliPercentageProgressBar extends ICliProgressBar {
955
+ /**
956
+ * Update the progress of the progress bar.
957
+ * @param progress The progress value (0–100). Values outside this range are clamped.
958
+ * @param options Optional: update type ('replace' or 'increment')
959
+ */
960
+ update: (progress: number, options?: CliPercentageProgressBarUpdateValueOptions) => void;
961
+ /**
962
+ * Complete the progress bar
963
+ * @returns void
964
+ */
965
+ complete: () => void;
966
+ /**
967
+ * Set the text of the spinner
968
+ * @param text The text to set
969
+ */
970
+ setText: (text: string) => void;
971
+ }
972
+ type CliTextAnimatorOptions = {
973
+ /**
974
+ * The speed of the animation
975
+ * @default 100
976
+ */
977
+ speed?: number;
978
+ /**
979
+ * The text will be removed after typing
980
+ */
981
+ removeAfterTyping?: boolean;
982
+ };
983
+ interface ICliTextAnimator extends ICliProgressBar {
984
+ /**
985
+ * Show animated text in a typing and erasing effect.
986
+ * @param text The text to animate
987
+ * @param options Optional: speed (ms per character), removeAfterTyping
988
+ * @returns A promise that resolves when the animation completes
989
+ */
990
+ showText: (text: string, options?: CliTextAnimatorOptions) => Promise<void>;
991
+ }
992
+
993
+ /**
994
+ * Represents a service that manages user sessions in the CLI
995
+ */
996
+ interface ICliUserSessionService {
997
+ /** Gets the current user session as a reactive stream */
998
+ getUserSession(): Observable<ICliUserSession | undefined>;
999
+ /** Sets the current user session */
1000
+ setUserSession(session: ICliUserSession): Promise<void>;
1001
+ /** Clears the current session (logout) */
1002
+ clearSession(): Promise<void>;
1003
+ /** Persists the current session to storage */
1004
+ persistSession(): Promise<void>;
1005
+ /** Restores a session from storage (called on boot) */
1006
+ restoreSession(): Promise<ICliUserSession | undefined>;
1007
+ }
1008
+ /**
1009
+ * Represents a service that manages users in the CLI
1010
+ */
1011
+ interface ICliUsersStoreService {
1012
+ /** Gets users with optional filtering and pagination */
1013
+ getUsers(options?: {
1014
+ query?: string;
1015
+ skip?: number;
1016
+ take?: number;
1017
+ }): Observable<ICliUser[]>;
1018
+ /** Creates a new user */
1019
+ createUser(user: CliAddUser): Promise<ICliUser>;
1020
+ /** Gets a user by id, name, or email */
1021
+ getUser(id: string): Observable<ICliUser | undefined>;
1022
+ /** Updates an existing user */
1023
+ updateUser(id: string, updates: CliUpdateUser): Promise<ICliUser>;
1024
+ /** Deletes a user by id */
1025
+ deleteUser(id: string): Promise<void>;
1026
+ }
1027
+ /**
1028
+ * Represents a service that manages groups in the CLI
1029
+ */
1030
+ interface ICliGroupsStoreService {
1031
+ /** Gets all groups */
1032
+ getGroups(): Observable<ICliGroup[]>;
1033
+ /** Gets a group by id or name */
1034
+ getGroup(id: string): Observable<ICliGroup | undefined>;
1035
+ /** Creates a new group */
1036
+ createGroup(name: string, description?: string): Promise<ICliGroup>;
1037
+ /** Deletes a group by id */
1038
+ deleteGroup(id: string): Promise<void>;
1039
+ /** Gets all users that belong to a group */
1040
+ getGroupMembers(groupId: string): Observable<ICliUser[]>;
1041
+ }
1042
+ /**
1043
+ * Represents a service that handles authentication in the CLI
1044
+ */
1045
+ interface ICliAuthService {
1046
+ /** Authenticates a user and returns a session */
1047
+ login(username: string, password: string): Promise<ICliUserSession>;
1048
+ /** Ends the current session */
1049
+ logout(): Promise<void>;
1050
+ /** Sets or updates a user's password */
1051
+ setPassword(userId: string, password: string): Promise<void>;
1052
+ /** Verifies a password against stored credentials */
1053
+ verifyPassword(userId: string, password: string): Promise<boolean>;
1054
+ /** Hashes a password with a salt using Web Crypto SHA-256 */
1055
+ hashPassword(password: string, salt: string): Promise<string>;
1056
+ }
1057
+
1058
+ /**
1059
+ * Represents a serialized snapshot of a CLI engine's state.
1060
+ * Used to duplicate terminal tabs with full state preservation.
1061
+ */
1062
+ interface CliEngineSnapshot {
1063
+ /** Schema version for forward compatibility */
1064
+ version: 1;
1065
+ /** Timestamp (ms since epoch) when the snapshot was taken */
1066
+ timestamp: number;
1067
+ /** Serialized terminal state */
1068
+ terminal: {
1069
+ /** Terminal buffer serialized via @xterm/addon-serialize */
1070
+ serializedBuffer: string;
1071
+ /** Terminal column count at time of snapshot */
1072
+ cols: number;
1073
+ /** Terminal row count at time of snapshot */
1074
+ rows: number;
1075
+ };
1076
+ /** Command history entries (most recent last) */
1077
+ commandHistory: string[];
1078
+ /** Named state store entries */
1079
+ stateStores: Array<{
1080
+ name: string;
1081
+ state: Record<string, any>;
1082
+ }>;
1083
+ }
1084
+
1085
+ /**
1086
+ * Background service lifecycle type.
1087
+ * - `'daemon'` — Long-running service whose `onStart` blocks until the abort signal
1088
+ * fires. Suitable for event loops, polling, or WebSocket connections. Can be
1089
+ * stopped and restarted.
996
1090
  * - `'job'` — Run-to-completion task whose `onStart` resolves when the work is done.
997
1091
  * Automatically transitions to `'done'` status on success. Cannot be restarted.
998
1092
  */
@@ -1122,6 +1216,485 @@ interface ICliBackgroundServiceRegistry {
1122
1216
  destroyAll(): Promise<void>;
1123
1217
  }
1124
1218
 
1219
+ /**
1220
+ * Messages sent from the main thread to a background service Worker.
1221
+ */
1222
+ type CliWorkerInboundMessage = {
1223
+ type: 'start';
1224
+ config?: Record<string, unknown>;
1225
+ } | {
1226
+ type: 'stop';
1227
+ } | {
1228
+ type: 'abort';
1229
+ };
1230
+ /**
1231
+ * Messages sent from a background service Worker to the main thread.
1232
+ */
1233
+ type CliWorkerOutboundMessage = {
1234
+ type: 'log';
1235
+ level: 'info' | 'warn' | 'error';
1236
+ message: string;
1237
+ } | {
1238
+ type: 'event';
1239
+ event: Omit<ICliServiceEvent, 'timestamp'>;
1240
+ } | {
1241
+ type: 'state-update';
1242
+ patch: Record<string, unknown>;
1243
+ } | {
1244
+ type: 'status';
1245
+ status: CliBackgroundServiceStatus;
1246
+ } | {
1247
+ type: 'error';
1248
+ message: string;
1249
+ stack?: string;
1250
+ };
1251
+
1252
+ /**
1253
+ * Represents an entry in a file listing.
1254
+ */
1255
+ interface ICliFileEntry {
1256
+ name: string;
1257
+ type: 'file' | 'directory';
1258
+ size: number;
1259
+ modified: string;
1260
+ }
1261
+
1262
+ /**
1263
+ * Abstraction for file transfer operations.
1264
+ * Default implementation uses browser-native APIs (file picker, download dialog).
1265
+ * @qodalis/cli-files overrides with virtual FS backed by IndexedDB.
1266
+ */
1267
+ interface ICliFileTransferService {
1268
+ readFile(path: string): Promise<string | null>;
1269
+ writeFile(path: string, content: string): Promise<void>;
1270
+ listFiles(path: string): Promise<ICliFileEntry[]>;
1271
+ exists(path: string): Promise<boolean>;
1272
+ downloadToBrowser(filename: string, content: string | Blob): void;
1273
+ uploadFromBrowser(accept?: string): Promise<{
1274
+ name: string;
1275
+ content: string;
1276
+ } | null>;
1277
+ }
1278
+
1279
+ interface ICliDragDropService {
1280
+ /** Emits an array of dropped File objects each time files are dropped onto the terminal */
1281
+ readonly onFileDrop: Observable<File[]>;
1282
+ }
1283
+
1284
+ /**
1285
+ * Opaque state value carried between lines during syntax highlighting.
1286
+ * Encodes context such as "inside a multi-line string" or "inside a block comment"
1287
+ * so the highlighter can resume correctly on the next line.
1288
+ * `0` typically represents the default/root state.
1289
+ */
1290
+ type LineState = number;
1291
+ interface ISyntaxHighlightRule {
1292
+ pattern: RegExp;
1293
+ tokenType: string;
1294
+ captureGroup?: number;
1295
+ }
1296
+ interface ISyntaxHighlighter {
1297
+ id: string;
1298
+ /** Human-readable language name (e.g. 'TypeScript'). Falls back to `id` when absent. */
1299
+ name?: string;
1300
+ extensions: string[];
1301
+ initialState: LineState;
1302
+ getRules(state: LineState): ISyntaxHighlightRule[];
1303
+ getNextLineState(line: string, currentState: LineState): LineState;
1304
+ }
1305
+ interface ISyntaxTheme {
1306
+ name: string;
1307
+ colors: Record<string, string>;
1308
+ }
1309
+
1310
+ /**
1311
+ * Represents a package source for the CLI package manager
1312
+ */
1313
+ interface CliPackageSource {
1314
+ /**
1315
+ * The name of the source, e.g. 'local', 'unpkg', 'jsdelivr'
1316
+ */
1317
+ name: string;
1318
+ /**
1319
+ * The base URL for fetching package files, e.g. 'http://localhost:3000/'
1320
+ */
1321
+ url: string;
1322
+ /**
1323
+ * The kind of source.
1324
+ * - 'registry': npm-compatible registry with search API (e.g. npmjs.org, Verdaccio)
1325
+ * - 'file': static file server, packages are discovered by probing known paths
1326
+ * @default 'file'
1327
+ */
1328
+ kind?: 'registry' | 'file';
1329
+ }
1330
+ /**
1331
+ * Represents a log level for the CLI
1332
+ */
1333
+ declare enum CliLogLevel {
1334
+ None = 0,
1335
+ DEBUG = 1,
1336
+ LOG = 2,
1337
+ INFO = 3,
1338
+ WARN = 4,
1339
+ ERROR = 5
1340
+ }
1341
+ /**
1342
+ * Options for the CLI
1343
+ */
1344
+ type CliOptions = Record<string, any> & {
1345
+ /**
1346
+ * Custom terminal options
1347
+ */
1348
+ terminalOptions?: ITerminalOptions & ITerminalInitOnlyOptions;
1349
+ /**
1350
+ * The minimum log level to display
1351
+ */
1352
+ logLevel?: CliLogLevel;
1353
+ /**
1354
+ * Custom package sources for the package manager.
1355
+ * Built-in sources (unpkg, jsdelivr) are always available.
1356
+ */
1357
+ packageSources?: {
1358
+ /**
1359
+ * Name of the primary source. Defaults to 'unpkg'.
1360
+ */
1361
+ primary?: string;
1362
+ /**
1363
+ * Additional custom sources
1364
+ */
1365
+ sources?: CliPackageSource[];
1366
+ };
1367
+ /**
1368
+ * Remote CLI servers to connect to.
1369
+ * Commands from each server are discovered and registered as proxy processors.
1370
+ */
1371
+ servers?: CliServerConfig[];
1372
+ /**
1373
+ * Whether the `eval` / `js` / `calc` command is enabled.
1374
+ * Disabled by default because it runs arbitrary JavaScript via `eval()`
1375
+ * in the host page context — a security risk in multi-tenant or
1376
+ * user-facing deployments.
1377
+ * @default false
1378
+ */
1379
+ allowEval?: boolean;
1380
+ };
1381
+ /**
1382
+ * Represents a package that can be installed
1383
+ */
1384
+ interface Package {
1385
+ /**
1386
+ * The name of the package
1387
+ */
1388
+ name: string;
1389
+ /**
1390
+ * The global name used to access the package
1391
+ */
1392
+ globalName?: string;
1393
+ /**
1394
+ * The version of the package
1395
+ */
1396
+ version: string;
1397
+ /**
1398
+ * The unpkg url to the package
1399
+ */
1400
+ url: string;
1401
+ /**
1402
+ * The dependencies for the module
1403
+ */
1404
+ dependencies?: Package[];
1405
+ }
1406
+ /**
1407
+ * Represents command processor metadata
1408
+ */
1409
+ type CliProcessorMetadata = Record<string, any> & {
1410
+ /**
1411
+ * If true, the processor is sealed and cannot be replaced or removed.
1412
+ * Sealed processors can still be extended (wrapped) by processors with `extendsProcessor = true`.
1413
+ */
1414
+ sealed?: boolean;
1415
+ /**
1416
+ * If true, the processor requires the server to be running
1417
+ */
1418
+ requireServer?: boolean;
1419
+ /**
1420
+ * The module the processor belongs to
1421
+ */
1422
+ module?: string;
1423
+ /**
1424
+ * An icon to display for the processor
1425
+ */
1426
+ icon?: CliIcon | string;
1427
+ /**
1428
+ * The minimum required version of @qodalis/cli-core for this processor.
1429
+ * If the installed core version is lower, the processor will be skipped during boot.
1430
+ */
1431
+ requiredCoreVersion?: string;
1432
+ /**
1433
+ * The minimum required version of @qodalis/cli for this processor.
1434
+ * If the installed CLI version is lower, the processor will be skipped during boot.
1435
+ */
1436
+ requiredCliVersion?: string;
1437
+ /**
1438
+ * If true, the processor is hidden from the help command listing.
1439
+ * The command still works when typed directly and `help <command>` still shows its details.
1440
+ */
1441
+ hidden?: boolean;
1442
+ };
1443
+ /**
1444
+ * Represents a state configuration for the CLI processor
1445
+ */
1446
+ type CliStateConfiguration = {
1447
+ /**
1448
+ * The initial state for the processor
1449
+ */
1450
+ initialState: Record<string, any>;
1451
+ /**
1452
+ * The store identifier for the processor, if any
1453
+ * @remarks If the store identifier is not set, the processor command name is used
1454
+ */
1455
+ storeName?: string;
1456
+ };
1457
+ type CliState = Record<string, any>;
1458
+ /**
1459
+ * Position of the CLI panel relative to the viewport edge.
1460
+ * - `'bottom'` — anchored to the bottom (default)
1461
+ * - `'top'` — anchored to the top
1462
+ * - `'left'` — anchored to the left (vertical layout)
1463
+ * - `'right'` — anchored to the right (vertical layout)
1464
+ */
1465
+ type CliPanelPosition = 'bottom' | 'top' | 'left' | 'right';
1466
+ /**
1467
+ * Alignment of the hidden-mode tab along its viewport edge.
1468
+ * - `'start'` — left for horizontal panels, top for vertical panels
1469
+ * - `'center'` — centered along the edge (default)
1470
+ * - `'end'` — right for horizontal panels, bottom for vertical panels
1471
+ */
1472
+ type CliPanelHideAlignment = 'start' | 'center' | 'end';
1473
+ /**
1474
+ * Configuration for the CLI panel component.
1475
+ */
1476
+ interface CliPanelConfig {
1477
+ /**
1478
+ * Whether the CLI should be collapsed by default.
1479
+ * @default true
1480
+ */
1481
+ isCollapsed?: boolean;
1482
+ /**
1483
+ * Whether the panel starts hidden (showing only the small tab/arrow).
1484
+ * @default false
1485
+ */
1486
+ isHidden?: boolean;
1487
+ /**
1488
+ * Position of the panel relative to the viewport.
1489
+ * @default 'bottom'
1490
+ */
1491
+ position?: CliPanelPosition;
1492
+ /**
1493
+ * Whether the close button is shown.
1494
+ * @default true
1495
+ */
1496
+ closable?: boolean;
1497
+ /**
1498
+ * Whether the panel can be resized by dragging.
1499
+ * @default true
1500
+ */
1501
+ resizable?: boolean;
1502
+ /**
1503
+ * Whether the hide button is shown. When hidden, the panel collapses
1504
+ * to a small tab at the viewport edge.
1505
+ * @default true
1506
+ */
1507
+ hideable?: boolean;
1508
+ /**
1509
+ * Alignment of the hide tab along the panel's viewport edge.
1510
+ * For bottom/top: 'start' = left, 'center', 'end' = right.
1511
+ * For left/right: 'start' = top, 'center', 'end' = bottom.
1512
+ * @default 'center'
1513
+ */
1514
+ hideAlignment?: CliPanelHideAlignment;
1515
+ /**
1516
+ * When true, the panel's chrome (header, border, background) automatically
1517
+ * syncs its colors with the active terminal theme. CSS custom properties
1518
+ * are derived from the xterm theme and applied as inline styles.
1519
+ * @default false
1520
+ */
1521
+ syncTheme?: boolean;
1522
+ }
1523
+
1524
+ /**
1525
+ * Framework-agnostic interface for programmatic control of the CLI panel.
1526
+ *
1527
+ * CliEngine is referenced as a generic to avoid a circular dependency
1528
+ * between @qodalis/cli-core and @qodalis/cli. Framework implementations
1529
+ * resolve this to the concrete CliEngine class.
1530
+ */
1531
+ interface ICliPanelRef<TEngine = unknown> {
1532
+ /** Expand the panel (sets collapsed=false). Initializes the first tab on first call. */
1533
+ open(): void;
1534
+ /** Collapse the panel body (sets collapsed=true). */
1535
+ collapse(): void;
1536
+ toggleCollapse(): void;
1537
+ /** Hide the panel to a small viewport-edge tab (reversible via unhide). */
1538
+ hide(): void;
1539
+ unhide(): void;
1540
+ toggleHide(): void;
1541
+ /** Destroy the panel (removes from DOM). Irreversible. */
1542
+ close(): void;
1543
+ maximize(): void;
1544
+ restore(): void;
1545
+ toggleMaximize(): void;
1546
+ /**
1547
+ * Set panel dimensions. Only the dimension relevant to the current
1548
+ * position is applied immediately (height for top/bottom, width for
1549
+ * left/right). The other dimension is stored for when the position changes.
1550
+ */
1551
+ resize(dimensions: {
1552
+ height?: number;
1553
+ width?: number;
1554
+ }): void;
1555
+ setPosition(position: CliPanelPosition): void;
1556
+ /** Create a new tab. Returns the new tab's ID. Title defaults to "Terminal {id}". */
1557
+ addTab(title?: string): number;
1558
+ /** Close a tab by ID. No-op if the ID does not exist. */
1559
+ closeTab(tabId: number): void;
1560
+ /** Activate a tab by ID. No-op if the ID does not exist. */
1561
+ selectTab(tabId: number): void;
1562
+ /** Programmatically rename a tab. No-op if the ID does not exist. */
1563
+ renameTab(tabId: number, title: string): void;
1564
+ /**
1565
+ * Split the active pane (or a pane within the specified tab) to create
1566
+ * a new pane to the right. Returns the new pane's ID.
1567
+ */
1568
+ splitPane(tabId?: number): number;
1569
+ /**
1570
+ * Close a pane by ID. Searches all tabs for the pane.
1571
+ * No-op if the ID does not exist.
1572
+ */
1573
+ closePane(paneId: number): void;
1574
+ /** Get the engine for a specific pane, or the active pane if omitted. */
1575
+ getEngine(paneId?: number): TEngine | undefined;
1576
+ getState(): CliPanelState;
1577
+ }
1578
+ interface CliPanelState {
1579
+ collapsed: boolean;
1580
+ hidden: boolean;
1581
+ maximized: boolean;
1582
+ position: CliPanelPosition;
1583
+ height: number;
1584
+ width: number;
1585
+ activeTabId: number;
1586
+ activePaneId: number;
1587
+ tabs: CliPanelTabState[];
1588
+ }
1589
+ interface CliPanelTabState {
1590
+ id: number;
1591
+ title: string;
1592
+ panes: CliPanelPaneState[];
1593
+ }
1594
+ interface CliPanelPaneState {
1595
+ id: number;
1596
+ widthPercent: number;
1597
+ }
1598
+
1599
+ /**
1600
+ * Options for HTTP client requests.
1601
+ * Extends standard RequestInit with convenience fields.
1602
+ */
1603
+ interface CliHttpRequestOptions extends Omit<RequestInit, 'method' | 'body'> {
1604
+ /**
1605
+ * Request timeout in milliseconds. When set, the request is automatically
1606
+ * aborted after this duration. Combines with any existing abort signal.
1607
+ */
1608
+ timeout?: number;
1609
+ }
1610
+ /**
1611
+ * HTTP client for making requests from command processors.
1612
+ *
1613
+ * Automatically merges the command's abort signal so that requests are
1614
+ * cancelled when the user presses Ctrl+C. Provides typed convenience
1615
+ * methods for common HTTP verbs as well as a raw `fetch()` for cases
1616
+ * that need full Response access (streaming, progress, etc.).
1617
+ *
1618
+ * Available on the execution context as `context.http`.
1619
+ *
1620
+ * @example
1621
+ * ```ts
1622
+ * // Typed JSON response
1623
+ * const users = await context.http.get<User[]>('https://api.example.com/users');
1624
+ *
1625
+ * // POST with body
1626
+ * await context.http.post('https://api.example.com/users', { name: 'John' });
1627
+ *
1628
+ * // Raw fetch for streaming
1629
+ * const response = await context.http.fetch('https://example.com/file.zip');
1630
+ * const reader = response.body?.getReader();
1631
+ * ```
1632
+ */
1633
+ interface ICliHttpClient {
1634
+ /**
1635
+ * Make a raw HTTP request. Returns the full Response object for cases
1636
+ * that need streaming, headers, or status inspection.
1637
+ * The command's abort signal is automatically merged.
1638
+ */
1639
+ fetch(url: string, init?: RequestInit): Promise<Response>;
1640
+ /**
1641
+ * HTTP GET request. Returns the parsed JSON response body.
1642
+ */
1643
+ get<T = any>(url: string, options?: CliHttpRequestOptions): Promise<T>;
1644
+ /**
1645
+ * HTTP POST request. Automatically serializes the body as JSON
1646
+ * (unless body is FormData, Blob, string, or ArrayBuffer).
1647
+ * Returns the parsed JSON response body.
1648
+ */
1649
+ post<T = any>(url: string, body?: any, options?: CliHttpRequestOptions): Promise<T>;
1650
+ /**
1651
+ * HTTP PUT request. Automatically serializes the body as JSON.
1652
+ * Returns the parsed JSON response body.
1653
+ */
1654
+ put<T = any>(url: string, body?: any, options?: CliHttpRequestOptions): Promise<T>;
1655
+ /**
1656
+ * HTTP PATCH request. Automatically serializes the body as JSON.
1657
+ * Returns the parsed JSON response body.
1658
+ */
1659
+ patch<T = any>(url: string, body?: any, options?: CliHttpRequestOptions): Promise<T>;
1660
+ /**
1661
+ * HTTP DELETE request. Returns the parsed JSON response body (if any).
1662
+ */
1663
+ delete<T = any>(url: string, options?: CliHttpRequestOptions): Promise<T>;
1664
+ /**
1665
+ * HTTP HEAD request. Returns the full Response (no body parsing).
1666
+ */
1667
+ head(url: string, options?: CliHttpRequestOptions): Promise<Response>;
1668
+ /**
1669
+ * HTTP OPTIONS request. Returns the parsed JSON response body.
1670
+ */
1671
+ options<T = any>(url: string, options?: CliHttpRequestOptions): Promise<T>;
1672
+ }
1673
+
1674
+ type CliNotificationLevel = 'info' | 'success' | 'warn' | 'error';
1675
+ interface CliNotification {
1676
+ level: CliNotificationLevel;
1677
+ message: string;
1678
+ timestamp: number;
1679
+ }
1680
+
1681
+ interface ICliNotifier {
1682
+ /** Set an info-level notification (progress, status updates). */
1683
+ info(message: string): void;
1684
+ /** Set a success-level notification. */
1685
+ success(message: string): void;
1686
+ /** Set a warn-level notification. */
1687
+ warn(message: string): void;
1688
+ /** Set an error-level notification. */
1689
+ error(message: string): void;
1690
+ /** Clear the current notification. */
1691
+ clear(): void;
1692
+ /** The current notification, or undefined if cleared. */
1693
+ readonly current: CliNotification | undefined;
1694
+ /** Observable that emits on every change (set or clear). */
1695
+ readonly change$: Observable<CliNotification | undefined>;
1696
+ }
1697
+
1125
1698
  /**
1126
1699
  * A managed timer handle returned by createInterval/createTimeout.
1127
1700
  * Managed timers are automatically cleared when full-screen mode exits
@@ -1214,6 +1787,27 @@ interface ICliExecutionContext {
1214
1787
  newLine?: boolean;
1215
1788
  keepCurrentLine?: boolean;
1216
1789
  }) => void;
1790
+ /**
1791
+ * Submit and execute a command — adds to history, runs the command,
1792
+ * and shows a new prompt afterwards. Used by both interactive input
1793
+ * and programmatic execution to ensure identical behaviour.
1794
+ */
1795
+ submitCommand(command: string): Promise<void>;
1796
+ /**
1797
+ * Notifier service for displaying status notifications in the panel header bar.
1798
+ * Supports severity levels: info, success, warn, error.
1799
+ * Cleared automatically when the command finishes.
1800
+ *
1801
+ * @example
1802
+ * ```ts
1803
+ * context.notifier.info('Downloading 45%...');
1804
+ * context.notifier.success('Connected to server');
1805
+ * context.notifier.warn('Rate limited, retrying...');
1806
+ * context.notifier.error('Connection failed');
1807
+ * context.notifier.clear();
1808
+ * ```
1809
+ */
1810
+ notifier: ICliNotifier;
1217
1811
  /**
1218
1812
  * Set the current processor as the context processor, i.e. the processor that will handle the command
1219
1813
  * @param processor The processor to set
@@ -1271,565 +1865,318 @@ interface ICliExecutionContext {
1271
1865
  /**
1272
1866
  * Optional callback that returns the current path to display in the prompt.
1273
1867
  * Any plugin can set this to customize the path segment of the prompt
1274
- * (e.g. a filesystem plugin showing the current working directory).
1275
- * When set, the returned path replaces the default `~` in the prompt.
1276
- * Return null to fall back to the default `~`.
1277
- */
1278
- promptPathProvider?: () => string | null;
1279
- /**
1280
- * Enter full-screen mode: switches to the alternate screen buffer,
1281
- * positions the cursor at row 1 col 1, and sets the given processor
1282
- * as the context processor so that all terminal input is routed to
1283
- * its `onData` method.
1284
- *
1285
- * By default the cursor is hidden (suitable for games / editors that
1286
- * manage their own cursor). Pass `{ showCursor: true }` to keep it
1287
- * visible (suitable for REPL / input-line interfaces).
1288
- *
1289
- * @param processor The processor that will handle all input in full-screen mode
1290
- * @param options Optional settings for full-screen mode
1291
- */
1292
- enterFullScreenMode: (processor: ICliCommandProcessor, options?: CliFullScreenOptions) => void;
1293
- /**
1294
- * Exit full-screen mode: restores the cursor, leaves the alternate screen buffer,
1295
- * clears the context processor, and re-displays the prompt.
1296
- */
1297
- exitFullScreenMode: () => void;
1298
- /**
1299
- * Creates a managed interval that is automatically cleared when full-screen
1300
- * mode exits or the CLI component is destroyed.
1301
- * @param callback The function to call on each interval tick
1302
- * @param ms The interval delay in milliseconds
1303
- * @returns A managed interval handle with clear() and setDelay() methods
1304
- */
1305
- createInterval: (callback: () => void, ms: number) => ICliManagedInterval;
1306
- /**
1307
- * Creates a managed timeout that is automatically cleared when full-screen
1308
- * mode exits or the CLI component is destroyed.
1309
- * @param callback The function to call when the timeout fires
1310
- * @param ms The timeout delay in milliseconds
1311
- * @returns A managed timer handle with a clear() method
1312
- */
1313
- createTimeout: (callback: () => void, ms: number) => ICliManagedTimer;
1314
- /**
1315
- * Registry for managing background services and jobs.
1316
- * Each CLI session owns its own isolated registry. Services registered here
1317
- * are scoped to this session and destroyed when the engine shuts down.
1318
- */
1319
- backgroundServices: ICliBackgroundServiceRegistry;
1320
- }
1321
-
1322
- interface ICliProcessorHook {
1323
- when: 'before' | 'after';
1324
- execute: (context: ICliExecutionContext) => Promise<void>;
1325
- }
1326
-
1327
- interface ICliCommandAuthor {
1328
- /**
1329
- * The name of the author
1330
- */
1331
- name: string;
1332
- /**
1333
- * The email of the author
1334
- */
1335
- email: string;
1336
- }
1337
- /**
1338
- * Represents a command parameter
1339
- */
1340
- interface ICliCommandParameterDescriptor {
1341
- /**
1342
- * The name of the parameter
1343
- */
1344
- name: string;
1345
- /**
1346
- * Aliases for the parameter
1347
- */
1348
- aliases?: string[];
1349
- /**
1350
- * A description of the parameter
1351
- */
1352
- description: string;
1353
- /**
1354
- * If true, the parameter is required
1355
- */
1356
- required: boolean;
1357
- /**
1358
- * The type of the parameter
1359
- */
1360
- type: 'string' | 'number' | 'boolean' | 'array' | 'object' | string;
1361
- /**
1362
- * The default value of the parameter
1363
- */
1364
- defaultValue?: any;
1365
- /**
1366
- * A validator function that validates the value of the parameter
1367
- * @param value The value to validate
1368
- * @returns An object with a valid property that indicates if the value is valid and an optional message property that contains a message to display if the value is not valid
1369
- */
1370
- validator?: (value: any) => {
1371
- /**
1372
- * Indicates if the value is valid
1373
- */
1374
- valid: boolean;
1375
- /**
1376
- * An optional message to display if the value is not valid
1377
- */
1378
- message?: string;
1379
- };
1380
- }
1381
- /**
1382
- * Represents a configuration option that a command processor exposes
1383
- * for management via the `configure` command.
1384
- */
1385
- interface ICliConfigurationOption {
1386
- /**
1387
- * The key used to store and retrieve this option, e.g. 'maxItems'
1388
- */
1389
- key: string;
1390
- /**
1391
- * Human-readable label shown in the interactive menu
1392
- */
1393
- label: string;
1394
- /**
1395
- * Description of what this option controls
1396
- */
1397
- description: string;
1398
- /**
1399
- * The data type of the option
1400
- */
1401
- type: 'string' | 'number' | 'boolean' | 'select';
1402
- /**
1403
- * The default value when no configuration has been set
1404
- */
1405
- defaultValue: any;
1406
- /**
1407
- * Available choices for 'select' type options
1408
- */
1409
- options?: {
1410
- label: string;
1411
- value: any;
1412
- }[];
1413
- /**
1414
- * Optional validator function
1415
- */
1416
- validator?: (value: any) => {
1417
- valid: boolean;
1418
- message?: string;
1419
- };
1420
- /**
1421
- * Override the category grouping (defaults to the processor command name)
1422
- */
1423
- category?: string;
1424
- }
1425
- /**
1426
- * Represents a command processor
1427
- */
1428
- interface ICliCommandProcessor {
1429
- /**
1430
- * The command that this processor handles
1431
- */
1432
- command: string;
1433
- /**
1434
- * Alternative names for the command
1435
- */
1436
- aliases?: string[];
1437
- /**
1438
- * A description of the command
1439
- */
1440
- description?: string;
1441
- /**
1442
- * The author of the command
1443
- */
1444
- author?: ICliCommandAuthor;
1445
- /**
1446
- * If true, the processor accepts raw text input after the command name as its value.
1447
- * The captured text is available via `command.value` in `processCommand`.
1448
- * @default false
1449
- * @remarks When true, any text following the command name is extracted as the command value
1450
- * rather than being interpreted as sub-commands. Use `valueRequired` instead if the value is mandatory.
1451
- */
1452
- acceptsRawInput?: boolean;
1453
- /**
1454
- * If true, the command requires some form of input before it can execute.
1455
- *
1456
- * The requirement is satisfied by **any** of:
1457
- * - A positional value (text after the command name, available via `command.value`)
1458
- * - Piped data from a previous command (available via `command.data`)
1459
- * - Named arguments (e.g. `--server=node --path=/app`)
1460
- *
1461
- * When set, `command.value` is automatically extracted from the raw input
1462
- * (equivalent to setting `acceptsRawInput`).
1463
- *
1464
- * Additionally, when positional input is present the engine skips
1465
- * required-parameter validation — the processor is responsible for
1466
- * parsing positional text into individual values. Required-parameter
1467
- * checks still apply when the user provides only named arguments.
1468
- *
1469
- * @default false
1470
- */
1471
- valueRequired?: boolean;
1472
- /**
1473
- * The version of the command processor
1474
- * @default '1.0.0'
1475
- */
1476
- version?: string;
1477
- /**
1478
- * The metadata for the command processor
1479
- */
1480
- metadata?: CliProcessorMetadata;
1481
- /**
1482
- * Processors that are nested under this processor
1483
- */
1484
- processors?: ICliCommandChildProcessor[];
1485
- /**
1486
- * Parameters that the command accepts
1487
- */
1488
- parameters?: ICliCommandParameterDescriptor[];
1489
- /**
1490
- * Hooks that are executed before and after the command is processed
1491
- */
1492
- hooks?: ICliProcessorHook[];
1493
- /**
1494
- * Represents the state configuration for the command processor
1495
- * @remarks The state configuration is used to store and retrieve state information for the command processor
1496
- * @remarks State configuration is optional and can be used to store and retrieve state information for the command processor
1497
- * @remarks The state configuration is used only for root command processors and not for child command processors
1498
- */
1499
- stateConfiguration?: CliStateConfiguration;
1500
- /**
1501
- * Configuration options exposed by this processor for the `configure` command.
1502
- * When defined, these options appear in the interactive configuration menu
1503
- * and can be managed via `configure get/set` subcommands.
1504
- */
1505
- configurationOptions?: ICliConfigurationOption[];
1506
- /**
1507
- * When true, this processor extends (wraps) an existing processor with the same
1508
- * command name instead of replacing it. The registry sets `originalProcessor`
1509
- * to the previous processor so this one can delegate to it.
1510
- */
1511
- extendsProcessor?: boolean;
1512
- /**
1513
- * Reference to the original processor that this one extends.
1514
- * Set automatically by the registry — do not set manually.
1515
- * Call `this.originalProcessor.processCommand(command, context)` to delegate.
1868
+ * (e.g. a filesystem plugin showing the current working directory).
1869
+ * When set, the returned path replaces the default `~` in the prompt.
1870
+ * Return null to fall back to the default `~`.
1516
1871
  */
1517
- originalProcessor?: ICliCommandProcessor;
1872
+ promptPathProvider?: () => string | null;
1518
1873
  /**
1519
- * Process the command
1520
- * @param command The command to process
1521
- * @param context The context in which the command is executed
1874
+ * Enter full-screen mode: switches to the alternate screen buffer,
1875
+ * positions the cursor at row 1 col 1, and sets the given processor
1876
+ * as the context processor so that all terminal input is routed to
1877
+ * its `onData` method.
1878
+ *
1879
+ * By default the cursor is hidden (suitable for games / editors that
1880
+ * manage their own cursor). Pass `{ showCursor: true }` to keep it
1881
+ * visible (suitable for REPL / input-line interfaces).
1882
+ *
1883
+ * @param processor The processor that will handle all input in full-screen mode
1884
+ * @param options Optional settings for full-screen mode
1522
1885
  */
1523
- processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
1886
+ enterFullScreenMode: (processor: ICliCommandProcessor, options?: CliFullScreenOptions) => void;
1524
1887
  /**
1525
- * Write the description of the command
1526
- * @param context The context in which the command is executed
1888
+ * Exit full-screen mode: restores the cursor, leaves the alternate screen buffer,
1889
+ * clears the context processor, and re-displays the prompt.
1527
1890
  */
1528
- writeDescription?(context: ICliExecutionContext): void;
1891
+ exitFullScreenMode: () => void;
1529
1892
  /**
1530
- * A function that validates the command before execution
1531
- * @param value The value to validate
1532
- * @returns An object with a valid property that indicates if the value is valid and an optional message property that contains a message to display if the value is not valid
1893
+ * Creates a managed interval that is automatically cleared when full-screen
1894
+ * mode exits or the CLI component is destroyed.
1895
+ * @param callback The function to call on each interval tick
1896
+ * @param ms The interval delay in milliseconds
1897
+ * @returns A managed interval handle with clear() and setDelay() methods
1533
1898
  */
1534
- validateBeforeExecution?: (command: CliProcessCommand, context: ICliExecutionContext) => {
1535
- valid: boolean;
1536
- message?: string;
1537
- };
1899
+ createInterval: (callback: () => void, ms: number) => ICliManagedInterval;
1538
1900
  /**
1539
- * Initialize the command processor
1540
- * @param context The context in which the command is executed
1901
+ * Creates a managed timeout that is automatically cleared when full-screen
1902
+ * mode exits or the CLI component is destroyed.
1903
+ * @param callback The function to call when the timeout fires
1904
+ * @param ms The timeout delay in milliseconds
1905
+ * @returns A managed timer handle with a clear() method
1541
1906
  */
1542
- initialize?(context: ICliExecutionContext): Promise<void>;
1907
+ createTimeout: (callback: () => void, ms: number) => ICliManagedTimer;
1543
1908
  /**
1544
- * Handle raw terminal data when this processor is the active context processor.
1545
- * When implemented, ALL terminal input is routed here instead of normal CLI input handling.
1546
- * Used for full-screen interactive modes (editors, pagers, etc.).
1547
- * @param data The raw terminal data string (escape sequences, control chars, printable text)
1548
- * @param context The execution context
1909
+ * Registry for managing background services and jobs.
1910
+ * Each CLI session owns its own isolated registry. Services registered here
1911
+ * are scoped to this session and destroyed when the engine shuts down.
1549
1912
  */
1550
- onData?(data: string, context: ICliExecutionContext): Promise<void>;
1913
+ backgroundServices: ICliBackgroundServiceRegistry;
1551
1914
  /**
1552
- * Called when the terminal is resized while this processor is the active
1553
- * full-screen context processor. Allows processors to adapt their rendering
1554
- * to the new terminal dimensions.
1555
- * @param cols The new number of columns
1556
- * @param rows The new number of rows
1557
- * @param context The execution context
1915
+ * HTTP client for making requests. Automatically wires the command's
1916
+ * abort signal so requests are cancelled on Ctrl+C.
1917
+ *
1918
+ * @example
1919
+ * ```ts
1920
+ * const data = await context.http.get<MyData>('https://api.example.com/data');
1921
+ * ```
1558
1922
  */
1559
- onResize?(cols: number, rows: number, context: ICliExecutionContext): void;
1923
+ http: ICliHttpClient;
1924
+ }
1925
+
1926
+ interface ICliProcessorHook {
1927
+ when: 'before' | 'after';
1928
+ execute: (context: ICliExecutionContext) => Promise<void>;
1929
+ }
1930
+
1931
+ interface ICliCommandAuthor {
1560
1932
  /**
1561
- * Called when the processor is being disposed — either because full-screen
1562
- * mode ended, the terminal disconnected, or the CLI component is being
1563
- * destroyed. Use this to clean up resources (timers, subscriptions, etc.).
1564
- * @param context The execution context
1933
+ * The name of the author
1565
1934
  */
1566
- onDispose?(context: ICliExecutionContext): void;
1567
- }
1568
- /**
1569
- * Represents a child command processor
1570
- */
1571
- interface ICliCommandChildProcessor extends ICliCommandProcessor {
1935
+ name: string;
1572
1936
  /**
1573
- * The parent processor, it is populated by the processor manager
1937
+ * The email of the author
1574
1938
  */
1575
- parent?: ICliCommandProcessor;
1939
+ email: string;
1576
1940
  }
1577
-
1578
1941
  /**
1579
- * Describes a global parameter (e.g. --help, --version) together with
1580
- * the handler that executes when the parameter is present.
1581
- *
1582
- * Global parameters are checked for every command before the command
1583
- * processor's own `processCommand` runs. If the handler returns `true`,
1584
- * command execution is halted (the parameter "consumed" the invocation).
1942
+ * Represents a command parameter
1585
1943
  */
1586
- interface ICliGlobalParameterHandler {
1944
+ interface ICliCommandParameterDescriptor {
1587
1945
  /**
1588
- * The parameter descriptor shown in help output and used for tab-completion.
1946
+ * The name of the parameter
1589
1947
  */
1590
- parameter: ICliCommandParameterDescriptor;
1948
+ name: string;
1591
1949
  /**
1592
- * Execution priority — lower values run first.
1593
- * @default 0
1950
+ * Aliases for the parameter
1594
1951
  */
1595
- priority?: number;
1952
+ aliases?: string[];
1596
1953
  /**
1597
- * Evaluate and optionally handle the parameter.
1598
- * @returns `true` to halt command execution, `false` to continue.
1954
+ * A description of the parameter
1599
1955
  */
1600
- handle(args: Record<string, any>, processor: ICliCommandProcessor, command: CliProcessCommand, context: ICliExecutionContext): boolean | Promise<boolean>;
1601
- }
1602
-
1603
- /**
1604
- * Represents a service that executes commands
1605
- */
1606
- interface ICliCommandExecutorService {
1956
+ description: string;
1607
1957
  /**
1608
- * Display the help output for a command, including its description,
1609
- * sub-commands, and parameters.
1610
- * @param command The parsed command to show help for
1611
- * @param context The execution context
1958
+ * If true, the parameter is required
1612
1959
  */
1613
- showHelp(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
1960
+ required: boolean;
1614
1961
  /**
1615
- * Execute a command
1616
- * @param command The command to execute
1617
- * @param context The context in which the command is executed
1962
+ * The type of the parameter
1618
1963
  */
1619
- executeCommand(command: string, context: ICliExecutionContext): Promise<void>;
1964
+ type: 'string' | 'number' | 'boolean' | 'array' | 'object' | string;
1620
1965
  /**
1621
- * Register a global parameter handler.
1622
- * Global parameters (e.g. --help, --version) are evaluated for every
1623
- * command before the processor's own processCommand runs.
1624
- * @param handler The global parameter handler to register
1966
+ * The default value of the parameter
1625
1967
  */
1626
- registerGlobalParameter(handler: ICliGlobalParameterHandler): void;
1968
+ defaultValue?: any;
1627
1969
  /**
1628
- * Returns the descriptors of all registered global parameters.
1629
- * Used by help output and tab-completion.
1970
+ * A validator function that validates the value of the parameter
1971
+ * @param value The value to validate
1972
+ * @returns An object with a valid property that indicates if the value is valid and an optional message property that contains a message to display if the value is not valid
1630
1973
  */
1631
- getGlobalParameters(): ICliCommandParameterDescriptor[];
1974
+ validator?: (value: any) => {
1975
+ /**
1976
+ * Indicates if the value is valid
1977
+ */
1978
+ valid: boolean;
1979
+ /**
1980
+ * An optional message to display if the value is not valid
1981
+ */
1982
+ message?: string;
1983
+ };
1632
1984
  }
1633
-
1634
1985
  /**
1635
- * Represents a registry for command processors
1986
+ * Represents a configuration option that a command processor exposes
1987
+ * for management via the `configure` command.
1636
1988
  */
1637
- interface ICliCommandProcessorRegistry {
1989
+ interface ICliConfigurationOption {
1638
1990
  /**
1639
- * The processors registered with the registry
1991
+ * The key used to store and retrieve this option, e.g. 'maxItems'
1640
1992
  */
1641
- readonly processors: ICliCommandProcessor[];
1993
+ key: string;
1642
1994
  /**
1643
- * Find a processor for a command
1644
- * @param mainCommand
1645
- * @param chainCommands
1995
+ * Human-readable label shown in the interactive menu
1646
1996
  */
1647
- findProcessor(mainCommand: string, chainCommands: string[]): ICliCommandProcessor | undefined;
1997
+ label: string;
1648
1998
  /**
1649
- * Recursively searches for a processor matching the given command.
1650
- * @param mainCommand The main command name.
1651
- * @param chainCommands The remaining chain commands (if any).
1652
- * @param processors The list of available processors.
1653
- * @returns The matching processor or undefined if not found.
1999
+ * Description of what this option controls
1654
2000
  */
1655
- findProcessorInCollection(mainCommand: string, chainCommands: string[], processors: ICliCommandProcessor[]): ICliCommandProcessor | undefined;
2001
+ description: string;
1656
2002
  /**
1657
- * Get the root processor for a child processor
1658
- * @param child The child processor
2003
+ * The data type of the option
1659
2004
  */
1660
- getRootProcessor(child: ICliCommandChildProcessor): ICliCommandProcessor;
2005
+ type: 'string' | 'number' | 'boolean' | 'select';
1661
2006
  /**
1662
- * Register a processor
1663
- * @param processor
2007
+ * The default value when no configuration has been set
1664
2008
  */
1665
- registerProcessor(processor: ICliCommandProcessor): void;
2009
+ defaultValue: any;
1666
2010
  /**
1667
- * Unregister a processor
1668
- * @param processor
2011
+ * Available choices for 'select' type options
1669
2012
  */
1670
- unregisterProcessor(processor: ICliCommandProcessor): void;
1671
- }
1672
- /**
1673
- * Represents a tracked CLI process entry
1674
- */
1675
- interface ICliProcessEntry {
1676
- pid: number;
1677
- /** Display name (service name for bg services, command text for commands) */
1678
- name: string;
1679
- /** Process type */
1680
- type: 'command' | 'daemon' | 'job' | 'service';
1681
- command: string;
1682
- startTime: number;
1683
- status: 'running' | 'completed' | 'failed' | 'killed';
1684
- exitCode?: number;
1685
- }
1686
- /** Options for registering a process */
1687
- interface ICliProcessRegisterOptions {
1688
- /** Display name (defaults to command) */
1689
- name?: string;
1690
- /** Process type (defaults to 'command') */
1691
- type?: 'command' | 'daemon' | 'job' | 'service';
1692
- /** Custom kill handler (e.g. for background services) */
1693
- onKill?: () => Promise<void> | void;
1694
- }
1695
- /**
1696
- * Registry for tracking CLI processes
1697
- */
1698
- interface ICliProcessRegistry {
1699
- /** Register a new process, returns assigned PID */
1700
- register(command: string, options?: ICliProcessRegisterOptions): {
1701
- pid: number;
1702
- abortController: AbortController;
2013
+ options?: {
2014
+ label: string;
2015
+ value: any;
2016
+ }[];
2017
+ /**
2018
+ * Optional validator function
2019
+ */
2020
+ validator?: (value: any) => {
2021
+ valid: boolean;
2022
+ message?: string;
1703
2023
  };
1704
- /** Mark process as completed */
1705
- complete(pid: number, exitCode: number): void;
1706
- /** Mark process as failed */
1707
- fail(pid: number): void;
1708
- /** Kill a process by PID */
1709
- kill(pid: number): boolean;
1710
- /** List all processes (running + recent completed) */
1711
- list(): ICliProcessEntry[];
1712
- /** Get the current foreground process PID */
1713
- readonly currentPid: number | undefined;
2024
+ /**
2025
+ * Override the category grouping (defaults to the processor command name)
2026
+ */
2027
+ category?: string;
1714
2028
  }
1715
-
1716
- interface ICliExecutionProcess {
2029
+ /**
2030
+ * Represents a command processor
2031
+ */
2032
+ interface ICliCommandProcessor {
1717
2033
  /**
1718
- * Indicates if the process has exited
2034
+ * The command that this processor handles
1719
2035
  */
1720
- exited?: boolean;
2036
+ command: string;
1721
2037
  /**
1722
- * The exit code of the process
2038
+ * Alternative names for the command
1723
2039
  */
1724
- exitCode?: number;
2040
+ aliases?: string[];
1725
2041
  /**
1726
- * Indicates if the process is running
2042
+ * A description of the command
1727
2043
  */
1728
- running: boolean;
2044
+ description?: string;
1729
2045
  /**
1730
- * The data of the process
2046
+ * The author of the command
1731
2047
  */
1732
- data: any | undefined;
2048
+ author?: ICliCommandAuthor;
1733
2049
  /**
1734
- * Exit the process
1735
- * @param code The exit code
1736
- * @returns void
2050
+ * If true, the processor accepts raw text input after the command name as its value.
2051
+ * The captured text is available via `command.value` in `processCommand`.
2052
+ * @default false
2053
+ * @remarks When true, any text following the command name is extracted as the command value
2054
+ * rather than being interpreted as sub-commands. Use `valueRequired` instead if the value is mandatory.
1737
2055
  */
1738
- exit: (
2056
+ acceptsRawInput?: boolean;
1739
2057
  /**
1740
- * The exit code
2058
+ * If true, the command requires some form of input before it can execute.
2059
+ *
2060
+ * The requirement is satisfied by **any** of:
2061
+ * - A positional value (text after the command name, available via `command.value`)
2062
+ * - Piped data from a previous command (available via `command.data`)
2063
+ * - Named arguments (e.g. `--server=node --path=/app`)
2064
+ *
2065
+ * When set, `command.value` is automatically extracted from the raw input
2066
+ * (equivalent to setting `acceptsRawInput`).
2067
+ *
2068
+ * Additionally, when positional input is present the engine skips
2069
+ * required-parameter validation — the processor is responsible for
2070
+ * parsing positional text into individual values. Required-parameter
2071
+ * checks still apply when the user provides only named arguments.
2072
+ *
2073
+ * @default false
1741
2074
  */
1742
- code?: number,
2075
+ valueRequired?: boolean;
1743
2076
  /**
1744
- * Options for exiting the process
2077
+ * The version of the command processor
2078
+ * @default '1.0.0'
1745
2079
  */
1746
- options?: {
1747
- /**
1748
- * Indicates if the exit should be silent, i.e. not throw an error
1749
- */
1750
- silent?: boolean;
1751
- }) => void;
2080
+ version?: string;
1752
2081
  /**
1753
- * Output data from the process
1754
- * @param data The data to output
2082
+ * The metadata for the command processor
1755
2083
  */
1756
- output(data: any): void;
1757
- }
1758
-
1759
- /**
1760
- * Represents a key-value store for the CLI
1761
- */
1762
- interface ICliKeyValueStore {
2084
+ metadata?: CliProcessorMetadata;
1763
2085
  /**
1764
- * Retrieves a value by key.
1765
- * @param key - The key to retrieve the value for.
1766
- * @returns A promise resolving to the value or undefined if not found.
2086
+ * Processors that are nested under this processor
1767
2087
  */
1768
- get<T = any>(key: string): Promise<T | undefined>;
2088
+ processors?: ICliCommandChildProcessor[];
1769
2089
  /**
1770
- * Sets a key-value pair in the store.
1771
- * @param key - The key to set.
1772
- * @param value - The value to store.
1773
- * @returns A promise resolving when the value is stored.
2090
+ * Parameters that the command accepts
1774
2091
  */
1775
- set(key: string, value: any): Promise<void>;
2092
+ parameters?: ICliCommandParameterDescriptor[];
1776
2093
  /**
1777
- * Removes a key-value pair by key.
1778
- * @param key - The key to remove.
1779
- * @returns A promise resolving when the key is removed.
2094
+ * Hooks that are executed before and after the command is processed
1780
2095
  */
1781
- remove(key: string): Promise<void>;
2096
+ hooks?: ICliProcessorHook[];
1782
2097
  /**
1783
- * Clears all key-value pairs from the store.
1784
- * @returns A promise resolving when the store is cleared.
2098
+ * Represents the state configuration for the command processor
2099
+ * @remarks The state configuration is used to store and retrieve state information for the command processor
2100
+ * @remarks State configuration is optional and can be used to store and retrieve state information for the command processor
2101
+ * @remarks The state configuration is used only for root command processors and not for child command processors
1785
2102
  */
1786
- clear(): Promise<void>;
1787
- }
1788
- /**
1789
- * Reactive state store scoped to a command processor or module.
1790
- *
1791
- * State is a plain object (`Record<string, any>`). Updates are shallow-merged
1792
- * (top-level keys are replaced, nested objects are not deep-merged).
1793
- * `getState()` returns a snapshot — mutating the returned object has no effect;
1794
- * always use `updateState()` to change state.
1795
- */
1796
- interface ICliStateStore {
2103
+ stateConfiguration?: CliStateConfiguration;
1797
2104
  /**
1798
- * Get a snapshot of the current state.
1799
- * @returns A shallow copy of the state object
2105
+ * Configuration options exposed by this processor for the `configure` command.
2106
+ * When defined, these options appear in the interactive configuration menu
2107
+ * and can be managed via `configure get/set` subcommands.
1800
2108
  */
1801
- getState<T extends CliState = CliState>(): T;
2109
+ configurationOptions?: ICliConfigurationOption[];
1802
2110
  /**
1803
- * Shallow-merge new values into the current state.
1804
- * Only the provided keys are updated; other keys are preserved.
1805
- * Triggers subscribers and persists if a storage backend is configured.
1806
- * @param newState Partial state to merge with the current state
2111
+ * When true, this processor extends (wraps) an existing processor with the same
2112
+ * command name instead of replacing it. The registry sets `originalProcessor`
2113
+ * to the previous processor so this one can delegate to it.
1807
2114
  */
1808
- updateState(newState: Partial<CliState>): void;
2115
+ extendsProcessor?: boolean;
1809
2116
  /**
1810
- * Select a specific property or computed value from the state.
1811
- * @param selector A function to project a slice of the state.
1812
- * @returns Observable of the selected value.
2117
+ * Reference to the original processor that this one extends.
2118
+ * Set automatically by the registry — do not set manually.
2119
+ * Call `this.originalProcessor.processCommand(command, context)` to delegate.
1813
2120
  */
1814
- select<K>(selector: (state: CliState) => K): Observable<K>;
2121
+ originalProcessor?: ICliCommandProcessor;
1815
2122
  /**
1816
- * Subscribe to state changes.
1817
- * @param callback Callback function to handle state changes.
1818
- * @returns Subscription object to manage the subscription.
2123
+ * Process the command
2124
+ * @param command The command to process
2125
+ * @param context The context in which the command is executed
1819
2126
  */
1820
- subscribe(callback: (state: CliState) => void): Subscription;
2127
+ processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
1821
2128
  /**
1822
- * Reset the state to its initial value.
2129
+ * Write the description of the command
2130
+ * @param context The context in which the command is executed
1823
2131
  */
1824
- reset(): void;
2132
+ writeDescription?(context: ICliExecutionContext): void;
1825
2133
  /**
1826
- * Persist the state to storage.
2134
+ * A function that validates the command before execution
2135
+ * @param value The value to validate
2136
+ * @returns An object with a valid property that indicates if the value is valid and an optional message property that contains a message to display if the value is not valid
1827
2137
  */
1828
- persist(): Promise<void>;
2138
+ validateBeforeExecution?: (command: CliProcessCommand, context: ICliExecutionContext) => {
2139
+ valid: boolean;
2140
+ message?: string;
2141
+ };
1829
2142
  /**
1830
- * Initialize the state from storage.
2143
+ * Initialize the command processor
2144
+ * @param context The context in which the command is executed
1831
2145
  */
1832
- initialize(): Promise<void>;
2146
+ initialize?(context: ICliExecutionContext): Promise<void>;
2147
+ /**
2148
+ * Handle raw terminal data when this processor is the active context processor.
2149
+ * When implemented, ALL terminal input is routed here instead of normal CLI input handling.
2150
+ * Used for full-screen interactive modes (editors, pagers, etc.).
2151
+ * @param data The raw terminal data string (escape sequences, control chars, printable text)
2152
+ * @param context The execution context
2153
+ */
2154
+ onData?(data: string, context: ICliExecutionContext): Promise<void>;
2155
+ /**
2156
+ * Called when the terminal is resized while this processor is the active
2157
+ * full-screen context processor. Allows processors to adapt their rendering
2158
+ * to the new terminal dimensions.
2159
+ * @param cols The new number of columns
2160
+ * @param rows The new number of rows
2161
+ * @param context The execution context
2162
+ */
2163
+ onResize?(cols: number, rows: number, context: ICliExecutionContext): void;
2164
+ /**
2165
+ * Called when the processor is being disposed — either because full-screen
2166
+ * mode ended, the terminal disconnected, or the CLI component is being
2167
+ * destroyed. Use this to clean up resources (timers, subscriptions, etc.).
2168
+ * @param context The execution context
2169
+ */
2170
+ onDispose?(context: ICliExecutionContext): void;
2171
+ }
2172
+ /**
2173
+ * Represents a child command processor
2174
+ */
2175
+ interface ICliCommandChildProcessor extends ICliCommandProcessor {
2176
+ /**
2177
+ * The parent processor, it is populated by the processor manager
2178
+ */
2179
+ parent?: ICliCommandProcessor;
1833
2180
  }
1834
2181
 
1835
2182
  /**
@@ -1974,446 +2321,354 @@ interface ICliLogger {
1974
2321
  * Log a debug message (DEBUG level)
1975
2322
  * @param args The arguments to log
1976
2323
  */
1977
- debug(...args: any[]): void;
1978
- }
1979
-
1980
- /**
1981
- * Provides internationalization (i18n) support for CLI strings.
1982
- */
1983
- interface ICliTranslationService {
1984
- /**
1985
- * Translate a key to the current locale.
1986
- * @param key The translation key (e.g. 'cli.echo.description')
1987
- * @param defaultValue The English fallback string (returned if no translation found)
1988
- * @param params Optional interpolation parameters for `{param}` placeholders
1989
- */
1990
- t(key: string, defaultValue: string, params?: Record<string, string | number>): string;
1991
- /**
1992
- * Get the current locale code (e.g. 'en', 'es', 'fr').
1993
- */
1994
- getLocale(): string;
1995
- /**
1996
- * Set the active locale.
1997
- * @param locale The locale code to switch to
1998
- */
1999
- setLocale(locale: string): void;
2000
- /**
2001
- * Register translations for a locale.
2002
- * Can be called multiple times — translations are merged, with later calls overriding earlier ones.
2003
- * @param locale The locale code
2004
- * @param translations Flat key-value map of translation keys to translated strings
2005
- */
2006
- addTranslations(locale: string, translations: Record<string, string>): void;
2007
- /**
2008
- * Get all locale codes that have at least one registered translation.
2009
- */
2010
- getAvailableLocales(): string[];
2011
- }
2012
- /**
2013
- * Dependency injection container for CLI services.
2014
- * Services are registered with string tokens and retrieved by type.
2015
- */
2016
- interface ICliServiceProvider {
2017
- /**
2018
- * Retrieve a service by its injection token.
2019
- * @param service The token (typically a `*_TOKEN` constant) identifying the service
2020
- * @returns The service instance, cast to `T`
2021
- * @throws If no service is registered for the given token
2022
- */
2023
- get<T = unknown>(service: any): T;
2024
- /**
2025
- * Register one or more service definitions.
2026
- * @param definition A single provider or an array of providers to register
2027
- */
2028
- set(definition: CliProvider | CliProvider[]): void;
2029
- }
2030
-
2031
- /**
2032
- * Abstract permission service for checking rwx permissions on resources.
2033
- * The default implementation lives in @qodalis/cli-users; consumers can
2034
- * replace it via the DI container.
2035
- */
2036
- interface ICliPermissionService {
2037
- /**
2038
- * Check whether a user may perform an action on a resource.
2039
- * @param user The acting user.
2040
- * @param action The requested operation.
2041
- * @param ownership Owner/group of the resource.
2042
- * @param permissions Permission string (e.g. "rwxr-xr-x").
2043
- * @returns true if allowed.
2044
- */
2045
- check(user: ICliUser, action: 'read' | 'write' | 'execute', ownership: ICliOwnership, permissions: string): boolean;
2046
- /** Parse octal (e.g. "755") to a permission string (e.g. "rwxr-xr-x"). */
2047
- parseOctal(octal: string): string;
2048
- /** Convert a permission string (e.g. "rwxr-xr-x") to octal (e.g. "755"). */
2049
- toOctal(permissions: string): string;
2324
+ debug(...args: any[]): void;
2050
2325
  }
2051
2326
 
2052
2327
  /**
2053
- * Context passed to completion providers describing the current input state.
2054
- */
2055
- interface ICliCompletionContext {
2056
- /** Full current line text */
2057
- input: string;
2058
- /** Cursor position in the line */
2059
- cursor: number;
2060
- /** The token (word) being completed at the cursor position */
2061
- token: string;
2062
- /** Start index of the token in the input string */
2063
- tokenStart: number;
2064
- /** Index of the token among all tokens (0 = command, 1+ = arguments) */
2065
- tokenIndex: number;
2066
- /** All tokens parsed from the input */
2067
- tokens: string[];
2068
- }
2069
- /**
2070
- * Provides tab-completion candidates for CLI input.
2071
- * Plugins can register providers to extend completion (e.g. file paths, custom values).
2328
+ * Provides internationalization (i18n) support for CLI strings.
2072
2329
  */
2073
- interface ICliCompletionProvider {
2330
+ interface ICliTranslationService {
2074
2331
  /**
2075
- * Priority order. Lower values are checked first.
2076
- * Built-in defaults: 100 (commands), 200 (parameters).
2077
- * Plugins should use lower values (e.g. 50) to take precedence for specific commands.
2332
+ * Translate a key to the current locale.
2333
+ * @param key The translation key (e.g. 'cli.echo.description')
2334
+ * @param defaultValue The English fallback string (returned if no translation found)
2335
+ * @param params Optional interpolation parameters for `{param}` placeholders
2078
2336
  */
2079
- priority: number;
2337
+ t(key: string, defaultValue: string, params?: Record<string, string | number>): string;
2080
2338
  /**
2081
- * Return completion candidates for the current input context.
2082
- * Return an empty array if this provider does not apply.
2339
+ * Get the current locale code (e.g. 'en', 'es', 'fr').
2083
2340
  */
2084
- getCompletions(context: ICliCompletionContext): string[] | Promise<string[]>;
2085
- }
2086
-
2087
- interface ICliProgressBar {
2341
+ getLocale(): string;
2088
2342
  /**
2089
- * Indicates if the progress bar is running
2343
+ * Set the active locale.
2344
+ * @param locale The locale code to switch to
2090
2345
  */
2091
- isRunning: boolean;
2346
+ setLocale(locale: string): void;
2092
2347
  /**
2093
- * Show the progress bar
2348
+ * Register translations for a locale.
2349
+ * Can be called multiple times — translations are merged, with later calls overriding earlier ones.
2350
+ * @param locale The locale code
2351
+ * @param translations Flat key-value map of translation keys to translated strings
2094
2352
  */
2095
- show: (text?: string) => void;
2353
+ addTranslations(locale: string, translations: Record<string, string>): void;
2096
2354
  /**
2097
- * Hide the progress bar
2355
+ * Get all locale codes that have at least one registered translation.
2098
2356
  */
2099
- hide: () => void;
2357
+ getAvailableLocales(): string[];
2100
2358
  }
2101
2359
  /**
2102
- * Represents a spinner for the CLI
2360
+ * Dependency injection container for CLI services.
2361
+ * Services are registered with string tokens and retrieved by type.
2103
2362
  */
2104
- interface ICliSpinner extends ICliProgressBar {
2363
+ interface ICliServiceProvider {
2105
2364
  /**
2106
- * Set the text of the spinner
2107
- * @param text The text to set
2365
+ * Retrieve a service by its injection token.
2366
+ * Returns `undefined` when no provider is registered for the token.
2367
+ * For multi-provider tokens, returns the last registered value (use `getAll` for the full array).
2368
+ * @param service The token (typically a `*_TOKEN` constant) identifying the service
2369
+ * @returns The service instance cast to `T`, or `undefined` if not registered
2108
2370
  */
2109
- setText: (text: string) => void;
2110
- }
2111
- type CliPercentageProgressBarUpdateValueOptions = {
2371
+ get<T = unknown>(service: any): T | undefined;
2112
2372
  /**
2113
- * The type of update to perform
2114
- * @default 'replace'
2373
+ * Retrieve all registered services for a multi-provider token.
2374
+ * Returns an empty array when no provider is registered for the token.
2375
+ * @param service The token (typically a `*_TOKEN` constant) identifying the service
2376
+ * @returns Array of all resolved service instances
2115
2377
  */
2116
- type?: 'replace' | 'increment';
2117
- };
2118
- /**
2119
- * Represents a progress bar for the CLI
2120
- */
2121
- interface ICliPercentageProgressBar extends ICliProgressBar {
2378
+ getAll<T = unknown>(service: any): T[];
2122
2379
  /**
2123
- * Update the progress of the progress bar.
2124
- * @param progress The progress value (0–100). Values outside this range are clamped.
2125
- * @param options Optional: update type ('replace' or 'increment')
2380
+ * Retrieve a service by its injection token, throwing if not registered.
2381
+ * Use this when the service is required and its absence is a programming error.
2382
+ * For multi-provider tokens, returns the last registered value (use `getAll` for the full array).
2383
+ * @param service The token (typically a `*_TOKEN` constant) identifying the service
2384
+ * @returns The service instance, cast to `T`
2385
+ * @throws If no service is registered for the given token
2126
2386
  */
2127
- update: (progress: number, options?: CliPercentageProgressBarUpdateValueOptions) => void;
2387
+ getRequired<T = unknown>(service: any): T;
2128
2388
  /**
2129
- * Complete the progress bar
2130
- * @returns void
2389
+ * Check whether a service is registered for the given token.
2390
+ * @param service The token identifying the service
2391
+ * @returns `true` if a service is registered, `false` otherwise
2131
2392
  */
2132
- complete: () => void;
2393
+ has(service: any): boolean;
2133
2394
  /**
2134
- * Set the text of the spinner
2135
- * @param text The text to set
2395
+ * Register one or more service definitions.
2396
+ * @param definition A single provider or an array of providers to register
2136
2397
  */
2137
- setText: (text: string) => void;
2398
+ set(definition: CliProvider | CliProvider[]): void;
2138
2399
  }
2139
- type CliTextAnimatorOptions = {
2140
- /**
2141
- * The speed of the animation
2142
- * @default 100
2143
- */
2144
- speed?: number;
2400
+ /** DI token for `ICliServerAuthTokenProvider` (multi-provider) */
2401
+ declare const ICliServerAuthTokenProvider_TOKEN = "cli-server-auth-token-provider";
2402
+ /** DI token for `ICliServerAuthService` */
2403
+ declare const ICliServerAuthService_TOKEN = "cli-server-auth-service";
2404
+ /**
2405
+ * Integrators implement this interface to supply auth credentials
2406
+ * for server requests. Multiple providers can be registered — the
2407
+ * auth service merges headers from all of them (later providers
2408
+ * override earlier ones for the same header name).
2409
+ *
2410
+ * @example
2411
+ * ```ts
2412
+ * class MyAuthProvider implements ICliServerAuthTokenProvider {
2413
+ * getHeaders(serverName: string) {
2414
+ * return { Authorization: `Bearer ${this.oauthService.getAccessToken()}` };
2415
+ * }
2416
+ * }
2417
+ *
2418
+ * // Register in a module:
2419
+ * const myModule: ICliModule = {
2420
+ * name: 'my-auth',
2421
+ * services: [{
2422
+ * provide: ICliServerAuthTokenProvider_TOKEN,
2423
+ * useValue: new MyAuthProvider(),
2424
+ * multi: true,
2425
+ * }],
2426
+ * };
2427
+ * ```
2428
+ */
2429
+ interface ICliServerAuthTokenProvider {
2145
2430
  /**
2146
- * The text will be removed after typing
2431
+ * Return headers for a given server. Called on every request,
2432
+ * so implementations can return fresh tokens.
2433
+ *
2434
+ * @param serverName The `name` field from `CliServerConfig`
2435
+ * @returns Headers to merge into the request, or an empty object
2147
2436
  */
2148
- removeAfterTyping?: boolean;
2149
- };
2150
- interface ICliTextAnimator extends ICliProgressBar {
2437
+ getHeaders(serverName: string): Record<string, string>;
2438
+ }
2439
+ /**
2440
+ * Internal service that resolves auth headers for a server by merging:
2441
+ * 1. Static/dynamic headers from `CliServerConfig.headers`
2442
+ * 2. Headers from all registered `ICliServerAuthTokenProvider`s
2443
+ *
2444
+ * Consumers should use this service instead of reading `config.headers` directly.
2445
+ */
2446
+ interface ICliServerAuthService {
2151
2447
  /**
2152
- * Show animated text in a typing and erasing effect.
2153
- * @param text The text to animate
2154
- * @param options Optional: speed (ms per character), removeAfterTyping
2155
- * @returns A promise that resolves when the animation completes
2448
+ * Resolve the final set of headers for a server request.
2449
+ * Merges config headers with all registered token providers.
2450
+ *
2451
+ * @param serverName The server's `name` field
2452
+ * @param configHeaders The `headers` field from `CliServerConfig`
2453
+ * @returns Merged headers ready for use in fetch/WebSocket calls
2156
2454
  */
2157
- showText: (text: string, options?: CliTextAnimatorOptions) => Promise<void>;
2455
+ getHeaders(serverName: string, configHeaders?: CliHeadersProvider): Record<string, string>;
2158
2456
  }
2159
2457
 
2160
2458
  /**
2161
- * Represents a service that manages user sessions in the CLI
2459
+ * A static header map or a function that returns one.
2460
+ * Use a function when headers contain short-lived tokens (e.g. JWTs)
2461
+ * so that every request gets a fresh value.
2462
+ *
2463
+ * @example
2464
+ * // Static
2465
+ * headers: { 'X-Api-Key': 'abc123' }
2466
+ *
2467
+ * // Dynamic (token refresh)
2468
+ * headers: () => ({ Authorization: `Bearer ${auth.getToken()}` })
2162
2469
  */
2163
- interface ICliUserSessionService {
2164
- /** Gets the current user session as a reactive stream */
2165
- getUserSession(): Observable<ICliUserSession | undefined>;
2166
- /** Sets the current user session */
2167
- setUserSession(session: ICliUserSession): Promise<void>;
2168
- /** Clears the current session (logout) */
2169
- clearSession(): Promise<void>;
2170
- /** Persists the current session to storage */
2171
- persistSession(): Promise<void>;
2172
- /** Restores a session from storage (called on boot) */
2173
- restoreSession(): Promise<ICliUserSession | undefined>;
2174
- }
2470
+ type CliHeadersProvider = Record<string, string> | (() => Record<string, string>);
2175
2471
  /**
2176
- * Represents a service that manages users in the CLI
2472
+ * Resolves a CliHeadersProvider to a plain header map.
2177
2473
  */
2178
- interface ICliUsersStoreService {
2179
- /** Gets users with optional filtering and pagination */
2180
- getUsers(options?: {
2181
- query?: string;
2182
- skip?: number;
2183
- take?: number;
2184
- }): Observable<ICliUser[]>;
2185
- /** Creates a new user */
2186
- createUser(user: CliAddUser): Promise<ICliUser>;
2187
- /** Gets a user by id, name, or email */
2188
- getUser(id: string): Observable<ICliUser | undefined>;
2189
- /** Updates an existing user */
2190
- updateUser(id: string, updates: CliUpdateUser): Promise<ICliUser>;
2191
- /** Deletes a user by id */
2192
- deleteUser(id: string): Promise<void>;
2193
- }
2474
+ declare function resolveHeaders(provider?: CliHeadersProvider): Record<string, string>;
2194
2475
  /**
2195
- * Represents a service that manages groups in the CLI
2476
+ * Resolves auth headers for a server request using the auth service if available,
2477
+ * otherwise falls back to resolving config headers directly.
2478
+ *
2479
+ * This is the single entry point plugins should use to get headers for server requests.
2480
+ *
2481
+ * @param services The service provider (from context.services)
2482
+ * @param serverName The server name
2483
+ * @param configHeaders The headers from CliServerConfig
2484
+ * @returns Resolved headers ready for use
2196
2485
  */
2197
- interface ICliGroupsStoreService {
2198
- /** Gets all groups */
2199
- getGroups(): Observable<ICliGroup[]>;
2200
- /** Gets a group by id or name */
2201
- getGroup(id: string): Observable<ICliGroup | undefined>;
2202
- /** Creates a new group */
2203
- createGroup(name: string, description?: string): Promise<ICliGroup>;
2204
- /** Deletes a group by id */
2205
- deleteGroup(id: string): Promise<void>;
2206
- /** Gets all users that belong to a group */
2207
- getGroupMembers(groupId: string): Observable<ICliUser[]>;
2208
- }
2486
+ declare function resolveServerHeaders(services: ICliServiceProvider | undefined, serverName: string, configHeaders?: CliHeadersProvider): Record<string, string>;
2209
2487
  /**
2210
- * Represents a service that handles authentication in the CLI
2488
+ * Configuration for a remote CLI server
2211
2489
  */
2212
- interface ICliAuthService {
2213
- /** Authenticates a user and returns a session */
2214
- login(username: string, password: string): Promise<ICliUserSession>;
2215
- /** Ends the current session */
2216
- logout(): Promise<void>;
2217
- /** Sets or updates a user's password */
2218
- setPassword(userId: string, password: string): Promise<void>;
2219
- /** Verifies a password against stored credentials */
2220
- verifyPassword(userId: string, password: string): Promise<boolean>;
2221
- /** Hashes a password with a salt using Web Crypto SHA-256 */
2222
- hashPassword(password: string, salt: string): Promise<string>;
2223
- }
2224
-
2490
+ type CliServerConfig = {
2491
+ /** Unique identifier, used for namespacing commands */
2492
+ name: string;
2493
+ /** Base URL of the server, e.g. "https://api.example.com" */
2494
+ url: string;
2495
+ /** Whether this server is enabled. @default true */
2496
+ enabled?: boolean;
2497
+ /**
2498
+ * Custom headers sent with every request (e.g. auth tokens).
2499
+ * Can be a static object or a function that returns fresh headers
2500
+ * on each call (useful for rotating tokens / JWTs).
2501
+ */
2502
+ headers?: CliHeadersProvider;
2503
+ /** Request timeout in milliseconds. @default 30000 */
2504
+ timeout?: number;
2505
+ };
2225
2506
  /**
2226
- * Represents a serialized snapshot of a CLI engine's state.
2227
- * Used to duplicate terminal tabs with full state preservation.
2507
+ * A single output item in a server response
2228
2508
  */
2229
- interface CliEngineSnapshot {
2230
- /** Schema version for forward compatibility */
2231
- version: 1;
2232
- /** Timestamp (ms since epoch) when the snapshot was taken */
2233
- timestamp: number;
2234
- /** Serialized terminal state */
2235
- terminal: {
2236
- /** Terminal buffer serialized via @xterm/addon-serialize */
2237
- serializedBuffer: string;
2238
- /** Terminal column count at time of snapshot */
2239
- cols: number;
2240
- /** Terminal row count at time of snapshot */
2241
- rows: number;
2242
- };
2243
- /** Command history entries (most recent last) */
2244
- commandHistory: string[];
2245
- /** Named state store entries */
2246
- stateStores: Array<{
2247
- name: string;
2248
- state: Record<string, any>;
2249
- }>;
2250
- }
2251
-
2509
+ type CliServerOutput = {
2510
+ type: 'text';
2511
+ value: string;
2512
+ style?: 'success' | 'error' | 'info' | 'warning';
2513
+ } | {
2514
+ type: 'table';
2515
+ headers: string[];
2516
+ rows: string[][];
2517
+ } | {
2518
+ type: 'list';
2519
+ items: string[];
2520
+ ordered?: boolean;
2521
+ } | {
2522
+ type: 'json';
2523
+ value: any;
2524
+ } | {
2525
+ type: 'key-value';
2526
+ entries: {
2527
+ key: string;
2528
+ value: string;
2529
+ }[];
2530
+ };
2531
+ /**
2532
+ * Structured response from a server command execution
2533
+ */
2534
+ type CliServerResponse = {
2535
+ exitCode: number;
2536
+ outputs: CliServerOutput[];
2537
+ };
2252
2538
  /**
2253
- * Messages sent from the main thread to a background service Worker.
2539
+ * Metadata about a remote command processor, returned by GET /api/qcli/commands
2254
2540
  */
2255
- type CliWorkerInboundMessage = {
2256
- type: 'start';
2257
- config?: Record<string, unknown>;
2258
- } | {
2259
- type: 'stop';
2260
- } | {
2261
- type: 'abort';
2541
+ type CliServerCommandDescriptor = {
2542
+ command: string;
2543
+ description?: string;
2544
+ version?: string;
2545
+ parameters?: {
2546
+ name: string;
2547
+ aliases?: string[];
2548
+ description: string;
2549
+ required: boolean;
2550
+ type: string;
2551
+ defaultValue?: any;
2552
+ }[];
2553
+ processors?: CliServerCommandDescriptor[];
2262
2554
  };
2263
2555
  /**
2264
- * Messages sent from a background service Worker to the main thread.
2556
+ * Server capabilities returned by GET /api/qcli/capabilities
2265
2557
  */
2266
- type CliWorkerOutboundMessage = {
2267
- type: 'log';
2268
- level: 'info' | 'warn' | 'error';
2269
- message: string;
2270
- } | {
2271
- type: 'event';
2272
- event: Omit<ICliServiceEvent, 'timestamp'>;
2273
- } | {
2274
- type: 'state-update';
2275
- patch: Record<string, unknown>;
2276
- } | {
2277
- type: 'status';
2278
- status: CliBackgroundServiceStatus;
2279
- } | {
2280
- type: 'error';
2281
- message: string;
2282
- stack?: string;
2558
+ type CliServerCapabilities = {
2559
+ /** Whether this server supports remote shell access */
2560
+ shell: boolean;
2561
+ /** Server operating system (e.g. "linux", "win32", "darwin") */
2562
+ os?: string;
2563
+ /** Path to the shell binary on the server */
2564
+ shellPath?: string;
2565
+ /** Server version string */
2566
+ version?: string;
2567
+ /** Whether this server supports SSE streaming execution */
2568
+ streaming?: boolean;
2569
+ };
2570
+
2571
+ type MultiServices = {
2572
+ /**
2573
+ * When true, injector returns an array of instances. This is useful to allow multiple
2574
+ * providers spread across many files to provide configuration information to a common token.
2575
+ */
2576
+ multi?: boolean;
2577
+ };
2578
+ type CliValueProvider = MultiServices & {
2579
+ useValue: any;
2283
2580
  };
2581
+ type CliTypeProvider = MultiServices & {
2582
+ useClass: any;
2583
+ /** DI tokens resolved from the container and passed as constructor arguments. */
2584
+ deps?: any[];
2585
+ };
2586
+ type CliFactoryProvider = MultiServices & {
2587
+ useFactory: Function;
2588
+ /** DI tokens resolved from the container and passed as factory arguments. */
2589
+ deps?: any[];
2590
+ };
2591
+ type CliProvider = {
2592
+ provide: any;
2593
+ /** When true, this token is sealed after registration and cannot be overwritten. */
2594
+ sealed?: boolean;
2595
+ /** When true, a new instance is created on every `get()` call instead of returning a singleton. */
2596
+ transient?: boolean;
2597
+ } & (CliValueProvider | CliTypeProvider | CliFactoryProvider) & Record<string, any>;
2284
2598
 
2285
2599
  /**
2286
- * Represents an entry in a file listing.
2600
+ * Represents a user in the CLI
2287
2601
  */
2288
- interface ICliFileEntry {
2602
+ interface ICliUser {
2603
+ /** Unique user identifier */
2604
+ id: string;
2605
+ /** Login name (unique) */
2289
2606
  name: string;
2290
- type: 'file' | 'directory';
2291
- size: number;
2292
- modified: string;
2607
+ /** Email address (unique) */
2608
+ email: string;
2609
+ /** Group IDs this user belongs to */
2610
+ groups: string[];
2611
+ /** Virtual home directory path, e.g. /home/root */
2612
+ homeDir?: string;
2613
+ /** Account creation timestamp */
2614
+ createdAt: number;
2615
+ /** Last modification timestamp */
2616
+ updatedAt: number;
2617
+ /** Whether the account is locked */
2618
+ disabled?: boolean;
2293
2619
  }
2294
-
2295
2620
  /**
2296
- * Abstraction for file transfer operations.
2297
- * Default implementation uses browser-native APIs (file picker, download dialog).
2298
- * @qodalis/cli-files overrides with virtual FS backed by IndexedDB.
2621
+ * Represents user credentials (shadow pattern — stored separately from ICliUser)
2299
2622
  */
2300
- interface ICliFileTransferService {
2301
- readFile(path: string): Promise<string | null>;
2302
- writeFile(path: string, content: string): Promise<void>;
2303
- listFiles(path: string): Promise<ICliFileEntry[]>;
2304
- exists(path: string): Promise<boolean>;
2305
- downloadToBrowser(filename: string, content: string | Blob): void;
2306
- uploadFromBrowser(accept?: string): Promise<{
2307
- name: string;
2308
- content: string;
2309
- } | null>;
2310
- }
2311
-
2312
- interface ICliDragDropService {
2313
- /** Emits an array of dropped File objects each time files are dropped onto the terminal */
2314
- readonly onFileDrop: Observable<File[]>;
2623
+ interface ICliUserCredentials {
2624
+ /** The user ID this credential belongs to */
2625
+ userId: string;
2626
+ /** SHA-256 hash of salt + password */
2627
+ passwordHash: string;
2628
+ /** Random salt for this user */
2629
+ salt: string;
2630
+ /** Timestamp of last password change */
2631
+ lastChanged: number;
2315
2632
  }
2316
-
2317
2633
  /**
2318
- * Opaque state value carried between lines during syntax highlighting.
2319
- * Encodes context such as "inside a multi-line string" or "inside a block comment"
2320
- * so the highlighter can resume correctly on the next line.
2321
- * `0` typically represents the default/root state.
2634
+ * Represents a group in the CLI
2322
2635
  */
2323
- type LineState = number;
2324
- interface ISyntaxHighlightRule {
2325
- pattern: RegExp;
2326
- tokenType: string;
2327
- captureGroup?: number;
2328
- }
2329
- interface ISyntaxHighlighter {
2636
+ interface ICliGroup {
2637
+ /** Unique group identifier */
2330
2638
  id: string;
2331
- /** Human-readable language name (e.g. 'TypeScript'). Falls back to `id` when absent. */
2332
- name?: string;
2333
- extensions: string[];
2334
- initialState: LineState;
2335
- getRules(state: LineState): ISyntaxHighlightRule[];
2336
- getNextLineState(line: string, currentState: LineState): LineState;
2337
- }
2338
- interface ISyntaxTheme {
2639
+ /** Group name (unique) */
2339
2640
  name: string;
2340
- colors: Record<string, string>;
2641
+ /** Optional group description */
2642
+ description?: string;
2643
+ /** Group creation timestamp */
2644
+ createdAt: number;
2341
2645
  }
2342
-
2343
2646
  /**
2344
- * Framework-agnostic interface for programmatic control of the CLI panel.
2345
- *
2346
- * CliEngine is referenced as a generic to avoid a circular dependency
2347
- * between @qodalis/cli-core and @qodalis/cli. Framework implementations
2348
- * resolve this to the concrete CliEngine class.
2647
+ * Represents an active user session
2349
2648
  */
2350
- interface ICliPanelRef<TEngine = unknown> {
2351
- /** Expand the panel (sets collapsed=false). Initializes the first tab on first call. */
2352
- open(): void;
2353
- /** Collapse the panel body (sets collapsed=true). */
2354
- collapse(): void;
2355
- toggleCollapse(): void;
2356
- /** Hide the panel to a small viewport-edge tab (reversible via unhide). */
2357
- hide(): void;
2358
- unhide(): void;
2359
- toggleHide(): void;
2360
- /** Destroy the panel (removes from DOM). Irreversible. */
2361
- close(): void;
2362
- maximize(): void;
2363
- restore(): void;
2364
- toggleMaximize(): void;
2365
- /**
2366
- * Set panel dimensions. Only the dimension relevant to the current
2367
- * position is applied immediately (height for top/bottom, width for
2368
- * left/right). The other dimension is stored for when the position changes.
2369
- */
2370
- resize(dimensions: {
2371
- height?: number;
2372
- width?: number;
2373
- }): void;
2374
- setPosition(position: CliPanelPosition): void;
2375
- /** Create a new tab. Returns the new tab's ID. Title defaults to "Terminal {id}". */
2376
- addTab(title?: string): number;
2377
- /** Close a tab by ID. No-op if the ID does not exist. */
2378
- closeTab(tabId: number): void;
2379
- /** Activate a tab by ID. No-op if the ID does not exist. */
2380
- selectTab(tabId: number): void;
2381
- /** Programmatically rename a tab. No-op if the ID does not exist. */
2382
- renameTab(tabId: number, title: string): void;
2383
- /**
2384
- * Split the active pane (or a pane within the specified tab) to create
2385
- * a new pane to the right. Returns the new pane's ID.
2386
- */
2387
- splitPane(tabId?: number): number;
2388
- /**
2389
- * Close a pane by ID. Searches all tabs for the pane.
2390
- * No-op if the ID does not exist.
2391
- */
2392
- closePane(paneId: number): void;
2393
- /** Get the engine for a specific pane, or the active pane if omitted. */
2394
- getEngine(paneId?: number): TEngine | undefined;
2395
- getState(): CliPanelState;
2396
- }
2397
- interface CliPanelState {
2398
- collapsed: boolean;
2399
- hidden: boolean;
2400
- maximized: boolean;
2401
- position: CliPanelPosition;
2402
- height: number;
2403
- width: number;
2404
- activeTabId: number;
2405
- activePaneId: number;
2406
- tabs: CliPanelTabState[];
2407
- }
2408
- interface CliPanelTabState {
2409
- id: number;
2410
- title: string;
2411
- panes: CliPanelPaneState[];
2412
- }
2413
- interface CliPanelPaneState {
2414
- id: number;
2415
- widthPercent: number;
2649
+ interface ICliUserSession {
2650
+ /** The user associated with this session */
2651
+ user: ICliUser;
2652
+ /** Pre-computed display name for the prompt (set by users module) */
2653
+ displayName?: string;
2654
+ /** Timestamp when the session started */
2655
+ loginTime: number;
2656
+ /** Timestamp of last activity */
2657
+ lastActivity: number;
2658
+ /** Extensible data (tokens, metadata, etc.) */
2659
+ data?: Record<string, any>;
2416
2660
  }
2661
+ /** Fields required to create a new user */
2662
+ type CliAddUser = Omit<ICliUser, 'id' | 'createdAt' | 'updatedAt'>;
2663
+ /** Fields that can be updated on a user */
2664
+ type CliUpdateUser = Partial<Omit<ICliUser, 'id' | 'createdAt'>>;
2665
+
2666
+ declare const enums: {
2667
+ CliForegroundColor: typeof CliForegroundColor;
2668
+ CliBackgroundColor: typeof CliBackgroundColor;
2669
+ CliIcon: typeof CliIcon;
2670
+ CliLogLevel: typeof CliLogLevel;
2671
+ };
2417
2672
 
2418
2673
  /**
2419
2674
  * Registry that tracks loaded web CLI modules (frontend plugins) and dispatches
@@ -2577,12 +2832,36 @@ declare class ServerVersionNegotiator {
2577
2832
  * Returns the negotiated API version and the base path for all subsequent calls,
2578
2833
  * or null if the server is unreachable or incompatible.
2579
2834
  */
2580
- static discover(baseUrl: string): Promise<{
2835
+ static discover(baseUrl: string, headers?: CliHeadersProvider): Promise<{
2581
2836
  apiVersion: number;
2582
2837
  basePath: string;
2583
2838
  } | null>;
2584
2839
  }
2585
2840
 
2841
+ /**
2842
+ * Builds a WebSocket URL that includes authentication credentials from headers
2843
+ * as query parameters. Since the browser WebSocket API does not support custom
2844
+ * request headers, this allows the host server's auth middleware to validate
2845
+ * the connection during the HTTP upgrade handshake.
2846
+ *
2847
+ * All configured headers are forwarded as query parameters prefixed with
2848
+ * `_header_` to avoid collisions with application-level query params.
2849
+ *
2850
+ * Accepts both static header maps and dynamic provider functions.
2851
+ *
2852
+ * **Security note:** Query parameters are visible in browser history, server
2853
+ * access logs, proxy/CDN logs, and the `Referer` header. Tokens placed in the
2854
+ * URL are therefore more exposed than those sent via HTTP headers. This is an
2855
+ * inherent limitation of the browser WebSocket API (no custom headers).
2856
+ * Server-side middleware that reads `_header_*` params should strip them from
2857
+ * logs and avoid forwarding them in redirects.
2858
+ *
2859
+ * @param wsUrl The base WebSocket URL (may already contain query parameters)
2860
+ * @param headers The headers provider from CliServerConfig (may include Authorization, etc.)
2861
+ * @returns The WebSocket URL with auth credentials appended as query parameters
2862
+ */
2863
+ declare function buildAuthenticatedWebSocketUrl(wsUrl: string, headers?: CliHeadersProvider): string;
2864
+
2586
2865
  /**
2587
2866
  * Derives CLI panel CSS custom property values from an xterm ITheme object.
2588
2867
  * Used when `syncTheme` is enabled on the panel config.
@@ -2623,10 +2902,11 @@ declare function nextPanelPosition(current: CliPanelPosition): CliPanelPosition;
2623
2902
  */
2624
2903
  declare function stripAnsi(text: string): string;
2625
2904
  /**
2626
- * Return the visible length of a string, ignoring ANSI escape codes.
2627
- * Useful for padding/alignment calculations in terminal output.
2905
+ * Return the visible (display) width of a string in terminal columns,
2906
+ * ignoring ANSI escape codes and accounting for wide characters (emoji,
2907
+ * East Asian fullwidth, etc.) that occupy two columns.
2628
2908
  * @param text The text potentially containing ANSI codes
2629
- * @returns The number of visible characters
2909
+ * @returns The number of terminal columns the text occupies
2630
2910
  */
2631
2911
  declare function visibleLength(text: string): number;
2632
2912
 
@@ -2782,7 +3062,7 @@ interface CliThemeInfo {
2782
3062
 
2783
3063
  declare const DefaultThemeInfos: Record<string, CliThemeInfo>;
2784
3064
 
2785
- declare const LIBRARY_VERSION = "2.0.0-beta.11";
3065
+ declare const LIBRARY_VERSION = "2.0.0-beta.13";
2786
3066
  declare const API_VERSION = 2;
2787
3067
 
2788
3068
  /**
@@ -2843,4 +3123,4 @@ declare class BrowserFileTransferService implements ICliFileTransferService {
2843
3123
  private _pickFile;
2844
3124
  }
2845
3125
 
2846
- export { API_VERSION, BrowserFileTransferService, CANCELLATION_ERROR_MESSAGE, CLI_CONFIGURE_STORE_NAME, CancellablePromise, type CliAddUser, CliBackgroundColor, type CliBackgroundServiceStatus, type CliBackgroundServiceType, type CliDateOptions, type CliEngineSnapshot, type CliFactoryProvider, type CliFilePickerOptions, type CliFileResult, CliForegroundColor, type CliFullScreenOptions, CliIcon, type CliLineOptions, CliLogLevel, CliModuleRegistry, type CliMultiSelectOption, type CliMultiSelectOptions, type CliNumberOptions, type CliOptions, type CliPackageSource, type CliPanelConfig, type CliPanelHideAlignment, type CliPanelPaneState, type CliPanelPosition, type CliPanelState, type CliPanelTabState, type CliPercentageProgressBarUpdateValueOptions, type CliProcessCommand, type CliProcessorMetadata, type CliProvider, type CliSelectOption, type CliSelectOptions, type CliServerCapabilities, type CliServerCommandDescriptor, type CliServerConfig, type CliServerOutput, type CliServerResponse, type CliServiceEventHandler, type CliServiceExecutionMode, type CliServiceLogLevel, type CliState, type CliStateConfiguration, type CliTableOptions, type CliTextAnimatorOptions, type CliTheme, type CliThemeCategory, type CliThemeInfo, type CliTypeProvider, type CliUpdateUser, type CliValueProvider, type CliWorkerInboundMessage, type CliWorkerOutboundMessage, DEFAULT_DIR_PERMISSIONS, DEFAULT_FILE_PERMISSIONS, DefaultLibraryAuthor, DefaultThemeInfos, DefaultThemes, type DefaultThemesType, type ICliAuthService, ICliAuthService_TOKEN, type ICliBackgroundService, type ICliBackgroundServiceInfo, type ICliBackgroundServiceRegistry, type ICliClipboard, type ICliCommandAuthor, type ICliCommandChildProcessor, type ICliCommandExecutorService, type ICliCommandParameterDescriptor, type ICliCommandProcessor, type ICliCommandProcessorRegistry, type ICliCompletionContext, type ICliCompletionProvider, ICliCompletionProvider_TOKEN, type ICliConfigurableModule, type ICliConfigurationOption, type ICliDragDropService, ICliDragDropService_TOKEN, type ICliExecutionContext, type ICliExecutionProcess, type ICliFileEntry, type ICliFilePickerProvider, ICliFilePickerProvider_TOKEN, type ICliFileTransferService, ICliFileTransferService_TOKEN, type ICliGlobalParameterHandler, type ICliGroup, type ICliGroupsStoreService, ICliGroupsStoreService_TOKEN, type ICliInputReader, type ICliKeyValueStore, type ICliLogger, type ICliManagedInterval, type ICliManagedTimer, type ICliModule, type ICliOwnership, type ICliPanelRef, type ICliPercentageProgressBar, type ICliPermissionService, ICliPermissionService_TOKEN, type ICliPingServerService, type ICliProcessEntry, type ICliProcessRegisterOptions, type ICliProcessRegistry, type ICliProcessorHook, type ICliProgressBar, type ICliServiceContext, type ICliServiceEvent, type ICliServiceLogEntry, type ICliServiceProvider, type ICliSpinner, type ICliStateStore, type ICliTerminalWriter, type ICliTextAnimator, type ICliTranslationService, ICliTranslationService_TOKEN, type ICliUmdModule, type ICliUser, type ICliUserCredentials, type ICliUserSession, type ICliUserSessionService, ICliUserSessionService_TOKEN, type ICliUsersStoreService, ICliUsersStoreService_TOKEN, type ISyntaxHighlightRule, type ISyntaxHighlighter, type ISyntaxTheme, LIBRARY_VERSION, type LineState, ObjectDescriber, type Package, type ServerVersionInfo, ServerVersionNegotiator, type WorkerServiceContext, bootCliModule, bootUmdModule, clearTerminalLine, colorFirstWord, colorizeJson, compareVersions, constants, createWorkerService, delay, derivePanelThemeStyles, enums, formatJson, getConfigValue, getParameterValue, getPluginConfigValue, getRightOfWord, highlightTextWithBg, initializeBrowserEnvironment, loadPanelPosition, nextPanelPosition, resolveConfigurationCategories, satisfiesMinVersion, satisfiesVersionRange, savePanelPosition, stripAnsi, toQueryString, utils, visibleLength };
3126
+ export { API_VERSION, BrowserFileTransferService, CANCELLATION_ERROR_MESSAGE, CLI_CONFIGURE_STORE_NAME, CancellablePromise, type CliAddUser, CliBackgroundColor, type CliBackgroundServiceStatus, type CliBackgroundServiceType, type CliDateOptions, type CliEngineSnapshot, type CliFactoryProvider, type CliFilePickerOptions, type CliFileResult, CliForegroundColor, type CliFullScreenOptions, type CliHeadersProvider, type CliHttpRequestOptions, CliIcon, type CliLineOptions, CliLogLevel, CliModuleRegistry, type CliMultiSelectOption, type CliMultiSelectOptions, type CliNotification, type CliNotificationLevel, type CliNumberOptions, type CliOptions, type CliPackageSource, type CliPanelConfig, type CliPanelHideAlignment, type CliPanelPaneState, type CliPanelPosition, type CliPanelState, type CliPanelTabState, type CliPercentageProgressBarUpdateValueOptions, type CliProcessCommand, type CliProcessorMetadata, type CliProvider, type CliSelectOption, type CliSelectOptions, type CliServerCapabilities, type CliServerCommandDescriptor, type CliServerConfig, type CliServerOutput, type CliServerResponse, type CliServiceEventHandler, type CliServiceExecutionMode, type CliServiceLogLevel, type CliState, type CliStateConfiguration, type CliTableOptions, type CliTextAnimatorOptions, type CliTheme, type CliThemeCategory, type CliThemeInfo, type CliTypeProvider, type CliUpdateUser, type CliValueProvider, type CliWorkerInboundMessage, type CliWorkerOutboundMessage, DEFAULT_DIR_PERMISSIONS, DEFAULT_FILE_PERMISSIONS, DefaultLibraryAuthor, DefaultThemeInfos, DefaultThemes, type DefaultThemesType, type ICliAuthService, ICliAuthService_TOKEN, type ICliBackgroundService, type ICliBackgroundServiceInfo, type ICliBackgroundServiceRegistry, type ICliClipboard, type ICliCommandAuthor, type ICliCommandChildProcessor, type ICliCommandExecutorService, type ICliCommandParameterDescriptor, type ICliCommandProcessor, type ICliCommandProcessorRegistry, type ICliCompletionContext, type ICliCompletionProvider, ICliCompletionProvider_TOKEN, type ICliConfigurableModule, type ICliConfigurationOption, type ICliDragDropService, ICliDragDropService_TOKEN, type ICliExecutionContext, type ICliExecutionProcess, type ICliFileEntry, type ICliFilePickerProvider, ICliFilePickerProvider_TOKEN, type ICliFileTransferService, ICliFileTransferService_TOKEN, type ICliGlobalParameterHandler, type ICliGroup, type ICliGroupsStoreService, ICliGroupsStoreService_TOKEN, type ICliHttpClient, ICliHttpClient_TOKEN, type ICliInputReader, type ICliKeyValueStore, type ICliLogger, type ICliManagedInterval, type ICliManagedTimer, type ICliModule, type ICliNotifier, type ICliOwnership, type ICliPanelRef, type ICliPercentageProgressBar, type ICliPermissionService, ICliPermissionService_TOKEN, type ICliPingServerService, type ICliProcessEntry, type ICliProcessRegisterOptions, type ICliProcessRegistry, type ICliProcessorHook, type ICliProgressBar, type ICliServerAuthService, ICliServerAuthService_TOKEN, type ICliServerAuthTokenProvider, ICliServerAuthTokenProvider_TOKEN, type ICliServiceContext, type ICliServiceEvent, type ICliServiceLogEntry, type ICliServiceProvider, type ICliSpinner, type ICliStateStore, type ICliTerminalWriter, type ICliTextAnimator, type ICliTranslationService, ICliTranslationService_TOKEN, type ICliUmdModule, type ICliUser, type ICliUserCredentials, type ICliUserSession, type ICliUserSessionService, ICliUserSessionService_TOKEN, type ICliUsersStoreService, ICliUsersStoreService_TOKEN, type ISyntaxHighlightRule, type ISyntaxHighlighter, type ISyntaxTheme, LIBRARY_VERSION, type LineState, ObjectDescriber, type Package, type ServerVersionInfo, ServerVersionNegotiator, type WorkerServiceContext, bootCliModule, bootUmdModule, buildAuthenticatedWebSocketUrl, clearTerminalLine, colorFirstWord, colorizeJson, compareVersions, constants, createWorkerService, delay, derivePanelThemeStyles, enums, formatJson, getConfigValue, getParameterValue, getPluginConfigValue, getRightOfWord, highlightTextWithBg, initializeBrowserEnvironment, loadPanelPosition, nextPanelPosition, resolveConfigurationCategories, resolveHeaders, resolveServerHeaders, satisfiesMinVersion, satisfiesVersionRange, savePanelPosition, stripAnsi, toQueryString, utils, visibleLength };