@qodalis/cli-core 2.0.0-beta.12 → 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.ts 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
@@ -1221,19 +1794,20 @@ interface ICliExecutionContext {
1221
1794
  */
1222
1795
  submitCommand(command: string): Promise<void>;
1223
1796
  /**
1224
- * Set a custom status text displayed in the panel header bar.
1225
- * Use to show progress or state (e.g. "Downloading 45%...", "Connected to server").
1797
+ * Notifier service for displaying status notifications in the panel header bar.
1798
+ * Supports severity levels: info, success, warn, error.
1226
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
+ * ```
1227
1809
  */
1228
- setStatusText(text: string): void;
1229
- /**
1230
- * Clear the custom status text from the panel header bar.
1231
- */
1232
- clearStatusText(): void;
1233
- /**
1234
- * Get the current custom status text, if any.
1235
- */
1236
- getStatusText(): string | undefined;
1810
+ notifier: ICliNotifier;
1237
1811
  /**
1238
1812
  * Set the current processor as the context processor, i.e. the processor that will handle the command
1239
1813
  * @param processor The processor to set
@@ -1291,565 +1865,318 @@ interface ICliExecutionContext {
1291
1865
  /**
1292
1866
  * Optional callback that returns the current path to display in the prompt.
1293
1867
  * Any plugin can set this to customize the path segment of the prompt
1294
- * (e.g. a filesystem plugin showing the current working directory).
1295
- * When set, the returned path replaces the default `~` in the prompt.
1296
- * Return null to fall back to the default `~`.
1297
- */
1298
- promptPathProvider?: () => string | null;
1299
- /**
1300
- * Enter full-screen mode: switches to the alternate screen buffer,
1301
- * positions the cursor at row 1 col 1, and sets the given processor
1302
- * as the context processor so that all terminal input is routed to
1303
- * its `onData` method.
1304
- *
1305
- * By default the cursor is hidden (suitable for games / editors that
1306
- * manage their own cursor). Pass `{ showCursor: true }` to keep it
1307
- * visible (suitable for REPL / input-line interfaces).
1308
- *
1309
- * @param processor The processor that will handle all input in full-screen mode
1310
- * @param options Optional settings for full-screen mode
1311
- */
1312
- enterFullScreenMode: (processor: ICliCommandProcessor, options?: CliFullScreenOptions) => void;
1313
- /**
1314
- * Exit full-screen mode: restores the cursor, leaves the alternate screen buffer,
1315
- * clears the context processor, and re-displays the prompt.
1316
- */
1317
- exitFullScreenMode: () => void;
1318
- /**
1319
- * Creates a managed interval that is automatically cleared when full-screen
1320
- * mode exits or the CLI component is destroyed.
1321
- * @param callback The function to call on each interval tick
1322
- * @param ms The interval delay in milliseconds
1323
- * @returns A managed interval handle with clear() and setDelay() methods
1324
- */
1325
- createInterval: (callback: () => void, ms: number) => ICliManagedInterval;
1326
- /**
1327
- * Creates a managed timeout that is automatically cleared when full-screen
1328
- * mode exits or the CLI component is destroyed.
1329
- * @param callback The function to call when the timeout fires
1330
- * @param ms The timeout delay in milliseconds
1331
- * @returns A managed timer handle with a clear() method
1332
- */
1333
- createTimeout: (callback: () => void, ms: number) => ICliManagedTimer;
1334
- /**
1335
- * Registry for managing background services and jobs.
1336
- * Each CLI session owns its own isolated registry. Services registered here
1337
- * are scoped to this session and destroyed when the engine shuts down.
1338
- */
1339
- backgroundServices: ICliBackgroundServiceRegistry;
1340
- }
1341
-
1342
- interface ICliProcessorHook {
1343
- when: 'before' | 'after';
1344
- execute: (context: ICliExecutionContext) => Promise<void>;
1345
- }
1346
-
1347
- interface ICliCommandAuthor {
1348
- /**
1349
- * The name of the author
1350
- */
1351
- name: string;
1352
- /**
1353
- * The email of the author
1354
- */
1355
- email: string;
1356
- }
1357
- /**
1358
- * Represents a command parameter
1359
- */
1360
- interface ICliCommandParameterDescriptor {
1361
- /**
1362
- * The name of the parameter
1363
- */
1364
- name: string;
1365
- /**
1366
- * Aliases for the parameter
1367
- */
1368
- aliases?: string[];
1369
- /**
1370
- * A description of the parameter
1371
- */
1372
- description: string;
1373
- /**
1374
- * If true, the parameter is required
1375
- */
1376
- required: boolean;
1377
- /**
1378
- * The type of the parameter
1379
- */
1380
- type: 'string' | 'number' | 'boolean' | 'array' | 'object' | string;
1381
- /**
1382
- * The default value of the parameter
1383
- */
1384
- defaultValue?: any;
1385
- /**
1386
- * A validator function that validates the value of the parameter
1387
- * @param value The value to validate
1388
- * @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
1389
- */
1390
- validator?: (value: any) => {
1391
- /**
1392
- * Indicates if the value is valid
1393
- */
1394
- valid: boolean;
1395
- /**
1396
- * An optional message to display if the value is not valid
1397
- */
1398
- message?: string;
1399
- };
1400
- }
1401
- /**
1402
- * Represents a configuration option that a command processor exposes
1403
- * for management via the `configure` command.
1404
- */
1405
- interface ICliConfigurationOption {
1406
- /**
1407
- * The key used to store and retrieve this option, e.g. 'maxItems'
1408
- */
1409
- key: string;
1410
- /**
1411
- * Human-readable label shown in the interactive menu
1412
- */
1413
- label: string;
1414
- /**
1415
- * Description of what this option controls
1416
- */
1417
- description: string;
1418
- /**
1419
- * The data type of the option
1420
- */
1421
- type: 'string' | 'number' | 'boolean' | 'select';
1422
- /**
1423
- * The default value when no configuration has been set
1424
- */
1425
- defaultValue: any;
1426
- /**
1427
- * Available choices for 'select' type options
1428
- */
1429
- options?: {
1430
- label: string;
1431
- value: any;
1432
- }[];
1433
- /**
1434
- * Optional validator function
1435
- */
1436
- validator?: (value: any) => {
1437
- valid: boolean;
1438
- message?: string;
1439
- };
1440
- /**
1441
- * Override the category grouping (defaults to the processor command name)
1442
- */
1443
- category?: string;
1444
- }
1445
- /**
1446
- * Represents a command processor
1447
- */
1448
- interface ICliCommandProcessor {
1449
- /**
1450
- * The command that this processor handles
1451
- */
1452
- command: string;
1453
- /**
1454
- * Alternative names for the command
1455
- */
1456
- aliases?: string[];
1457
- /**
1458
- * A description of the command
1459
- */
1460
- description?: string;
1461
- /**
1462
- * The author of the command
1463
- */
1464
- author?: ICliCommandAuthor;
1465
- /**
1466
- * If true, the processor accepts raw text input after the command name as its value.
1467
- * The captured text is available via `command.value` in `processCommand`.
1468
- * @default false
1469
- * @remarks When true, any text following the command name is extracted as the command value
1470
- * rather than being interpreted as sub-commands. Use `valueRequired` instead if the value is mandatory.
1471
- */
1472
- acceptsRawInput?: boolean;
1473
- /**
1474
- * If true, the command requires some form of input before it can execute.
1475
- *
1476
- * The requirement is satisfied by **any** of:
1477
- * - A positional value (text after the command name, available via `command.value`)
1478
- * - Piped data from a previous command (available via `command.data`)
1479
- * - Named arguments (e.g. `--server=node --path=/app`)
1480
- *
1481
- * When set, `command.value` is automatically extracted from the raw input
1482
- * (equivalent to setting `acceptsRawInput`).
1483
- *
1484
- * Additionally, when positional input is present the engine skips
1485
- * required-parameter validation — the processor is responsible for
1486
- * parsing positional text into individual values. Required-parameter
1487
- * checks still apply when the user provides only named arguments.
1488
- *
1489
- * @default false
1490
- */
1491
- valueRequired?: boolean;
1492
- /**
1493
- * The version of the command processor
1494
- * @default '1.0.0'
1495
- */
1496
- version?: string;
1497
- /**
1498
- * The metadata for the command processor
1499
- */
1500
- metadata?: CliProcessorMetadata;
1501
- /**
1502
- * Processors that are nested under this processor
1503
- */
1504
- processors?: ICliCommandChildProcessor[];
1505
- /**
1506
- * Parameters that the command accepts
1507
- */
1508
- parameters?: ICliCommandParameterDescriptor[];
1509
- /**
1510
- * Hooks that are executed before and after the command is processed
1511
- */
1512
- hooks?: ICliProcessorHook[];
1513
- /**
1514
- * Represents the state configuration for the command processor
1515
- * @remarks The state configuration is used to store and retrieve state information for the command processor
1516
- * @remarks State configuration is optional and can be used to store and retrieve state information for the command processor
1517
- * @remarks The state configuration is used only for root command processors and not for child command processors
1518
- */
1519
- stateConfiguration?: CliStateConfiguration;
1520
- /**
1521
- * Configuration options exposed by this processor for the `configure` command.
1522
- * When defined, these options appear in the interactive configuration menu
1523
- * and can be managed via `configure get/set` subcommands.
1524
- */
1525
- configurationOptions?: ICliConfigurationOption[];
1526
- /**
1527
- * When true, this processor extends (wraps) an existing processor with the same
1528
- * command name instead of replacing it. The registry sets `originalProcessor`
1529
- * to the previous processor so this one can delegate to it.
1530
- */
1531
- extendsProcessor?: boolean;
1532
- /**
1533
- * Reference to the original processor that this one extends.
1534
- * Set automatically by the registry — do not set manually.
1535
- * 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 `~`.
1536
1871
  */
1537
- originalProcessor?: ICliCommandProcessor;
1872
+ promptPathProvider?: () => string | null;
1538
1873
  /**
1539
- * Process the command
1540
- * @param command The command to process
1541
- * @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
1542
1885
  */
1543
- processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
1886
+ enterFullScreenMode: (processor: ICliCommandProcessor, options?: CliFullScreenOptions) => void;
1544
1887
  /**
1545
- * Write the description of the command
1546
- * @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.
1547
1890
  */
1548
- writeDescription?(context: ICliExecutionContext): void;
1891
+ exitFullScreenMode: () => void;
1549
1892
  /**
1550
- * A function that validates the command before execution
1551
- * @param value The value to validate
1552
- * @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
1553
1898
  */
1554
- validateBeforeExecution?: (command: CliProcessCommand, context: ICliExecutionContext) => {
1555
- valid: boolean;
1556
- message?: string;
1557
- };
1899
+ createInterval: (callback: () => void, ms: number) => ICliManagedInterval;
1558
1900
  /**
1559
- * Initialize the command processor
1560
- * @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
1561
1906
  */
1562
- initialize?(context: ICliExecutionContext): Promise<void>;
1907
+ createTimeout: (callback: () => void, ms: number) => ICliManagedTimer;
1563
1908
  /**
1564
- * Handle raw terminal data when this processor is the active context processor.
1565
- * When implemented, ALL terminal input is routed here instead of normal CLI input handling.
1566
- * Used for full-screen interactive modes (editors, pagers, etc.).
1567
- * @param data The raw terminal data string (escape sequences, control chars, printable text)
1568
- * @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.
1569
1912
  */
1570
- onData?(data: string, context: ICliExecutionContext): Promise<void>;
1913
+ backgroundServices: ICliBackgroundServiceRegistry;
1571
1914
  /**
1572
- * Called when the terminal is resized while this processor is the active
1573
- * full-screen context processor. Allows processors to adapt their rendering
1574
- * to the new terminal dimensions.
1575
- * @param cols The new number of columns
1576
- * @param rows The new number of rows
1577
- * @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
+ * ```
1578
1922
  */
1579
- 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 {
1580
1932
  /**
1581
- * Called when the processor is being disposed — either because full-screen
1582
- * mode ended, the terminal disconnected, or the CLI component is being
1583
- * destroyed. Use this to clean up resources (timers, subscriptions, etc.).
1584
- * @param context The execution context
1933
+ * The name of the author
1585
1934
  */
1586
- onDispose?(context: ICliExecutionContext): void;
1587
- }
1588
- /**
1589
- * Represents a child command processor
1590
- */
1591
- interface ICliCommandChildProcessor extends ICliCommandProcessor {
1935
+ name: string;
1592
1936
  /**
1593
- * The parent processor, it is populated by the processor manager
1937
+ * The email of the author
1594
1938
  */
1595
- parent?: ICliCommandProcessor;
1939
+ email: string;
1596
1940
  }
1597
-
1598
1941
  /**
1599
- * Describes a global parameter (e.g. --help, --version) together with
1600
- * the handler that executes when the parameter is present.
1601
- *
1602
- * Global parameters are checked for every command before the command
1603
- * processor's own `processCommand` runs. If the handler returns `true`,
1604
- * command execution is halted (the parameter "consumed" the invocation).
1942
+ * Represents a command parameter
1605
1943
  */
1606
- interface ICliGlobalParameterHandler {
1944
+ interface ICliCommandParameterDescriptor {
1607
1945
  /**
1608
- * The parameter descriptor shown in help output and used for tab-completion.
1946
+ * The name of the parameter
1609
1947
  */
1610
- parameter: ICliCommandParameterDescriptor;
1948
+ name: string;
1611
1949
  /**
1612
- * Execution priority — lower values run first.
1613
- * @default 0
1950
+ * Aliases for the parameter
1614
1951
  */
1615
- priority?: number;
1952
+ aliases?: string[];
1616
1953
  /**
1617
- * Evaluate and optionally handle the parameter.
1618
- * @returns `true` to halt command execution, `false` to continue.
1954
+ * A description of the parameter
1619
1955
  */
1620
- handle(args: Record<string, any>, processor: ICliCommandProcessor, command: CliProcessCommand, context: ICliExecutionContext): boolean | Promise<boolean>;
1621
- }
1622
-
1623
- /**
1624
- * Represents a service that executes commands
1625
- */
1626
- interface ICliCommandExecutorService {
1956
+ description: string;
1627
1957
  /**
1628
- * Display the help output for a command, including its description,
1629
- * sub-commands, and parameters.
1630
- * @param command The parsed command to show help for
1631
- * @param context The execution context
1958
+ * If true, the parameter is required
1632
1959
  */
1633
- showHelp(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
1960
+ required: boolean;
1634
1961
  /**
1635
- * Execute a command
1636
- * @param command The command to execute
1637
- * @param context The context in which the command is executed
1962
+ * The type of the parameter
1638
1963
  */
1639
- executeCommand(command: string, context: ICliExecutionContext): Promise<void>;
1964
+ type: 'string' | 'number' | 'boolean' | 'array' | 'object' | string;
1640
1965
  /**
1641
- * Register a global parameter handler.
1642
- * Global parameters (e.g. --help, --version) are evaluated for every
1643
- * command before the processor's own processCommand runs.
1644
- * @param handler The global parameter handler to register
1966
+ * The default value of the parameter
1645
1967
  */
1646
- registerGlobalParameter(handler: ICliGlobalParameterHandler): void;
1968
+ defaultValue?: any;
1647
1969
  /**
1648
- * Returns the descriptors of all registered global parameters.
1649
- * 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
1650
1973
  */
1651
- 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
+ };
1652
1984
  }
1653
-
1654
1985
  /**
1655
- * Represents a registry for command processors
1986
+ * Represents a configuration option that a command processor exposes
1987
+ * for management via the `configure` command.
1656
1988
  */
1657
- interface ICliCommandProcessorRegistry {
1989
+ interface ICliConfigurationOption {
1658
1990
  /**
1659
- * The processors registered with the registry
1991
+ * The key used to store and retrieve this option, e.g. 'maxItems'
1660
1992
  */
1661
- readonly processors: ICliCommandProcessor[];
1993
+ key: string;
1662
1994
  /**
1663
- * Find a processor for a command
1664
- * @param mainCommand
1665
- * @param chainCommands
1995
+ * Human-readable label shown in the interactive menu
1666
1996
  */
1667
- findProcessor(mainCommand: string, chainCommands: string[]): ICliCommandProcessor | undefined;
1997
+ label: string;
1668
1998
  /**
1669
- * Recursively searches for a processor matching the given command.
1670
- * @param mainCommand The main command name.
1671
- * @param chainCommands The remaining chain commands (if any).
1672
- * @param processors The list of available processors.
1673
- * @returns The matching processor or undefined if not found.
1999
+ * Description of what this option controls
1674
2000
  */
1675
- findProcessorInCollection(mainCommand: string, chainCommands: string[], processors: ICliCommandProcessor[]): ICliCommandProcessor | undefined;
2001
+ description: string;
1676
2002
  /**
1677
- * Get the root processor for a child processor
1678
- * @param child The child processor
2003
+ * The data type of the option
1679
2004
  */
1680
- getRootProcessor(child: ICliCommandChildProcessor): ICliCommandProcessor;
2005
+ type: 'string' | 'number' | 'boolean' | 'select';
1681
2006
  /**
1682
- * Register a processor
1683
- * @param processor
2007
+ * The default value when no configuration has been set
1684
2008
  */
1685
- registerProcessor(processor: ICliCommandProcessor): void;
2009
+ defaultValue: any;
1686
2010
  /**
1687
- * Unregister a processor
1688
- * @param processor
2011
+ * Available choices for 'select' type options
1689
2012
  */
1690
- unregisterProcessor(processor: ICliCommandProcessor): void;
1691
- }
1692
- /**
1693
- * Represents a tracked CLI process entry
1694
- */
1695
- interface ICliProcessEntry {
1696
- pid: number;
1697
- /** Display name (service name for bg services, command text for commands) */
1698
- name: string;
1699
- /** Process type */
1700
- type: 'command' | 'daemon' | 'job' | 'service';
1701
- command: string;
1702
- startTime: number;
1703
- status: 'running' | 'completed' | 'failed' | 'killed';
1704
- exitCode?: number;
1705
- }
1706
- /** Options for registering a process */
1707
- interface ICliProcessRegisterOptions {
1708
- /** Display name (defaults to command) */
1709
- name?: string;
1710
- /** Process type (defaults to 'command') */
1711
- type?: 'command' | 'daemon' | 'job' | 'service';
1712
- /** Custom kill handler (e.g. for background services) */
1713
- onKill?: () => Promise<void> | void;
1714
- }
1715
- /**
1716
- * Registry for tracking CLI processes
1717
- */
1718
- interface ICliProcessRegistry {
1719
- /** Register a new process, returns assigned PID */
1720
- register(command: string, options?: ICliProcessRegisterOptions): {
1721
- pid: number;
1722
- 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;
1723
2023
  };
1724
- /** Mark process as completed */
1725
- complete(pid: number, exitCode: number): void;
1726
- /** Mark process as failed */
1727
- fail(pid: number): void;
1728
- /** Kill a process by PID */
1729
- kill(pid: number): boolean;
1730
- /** List all processes (running + recent completed) */
1731
- list(): ICliProcessEntry[];
1732
- /** Get the current foreground process PID */
1733
- readonly currentPid: number | undefined;
2024
+ /**
2025
+ * Override the category grouping (defaults to the processor command name)
2026
+ */
2027
+ category?: string;
1734
2028
  }
1735
-
1736
- interface ICliExecutionProcess {
2029
+ /**
2030
+ * Represents a command processor
2031
+ */
2032
+ interface ICliCommandProcessor {
1737
2033
  /**
1738
- * Indicates if the process has exited
2034
+ * The command that this processor handles
1739
2035
  */
1740
- exited?: boolean;
2036
+ command: string;
1741
2037
  /**
1742
- * The exit code of the process
2038
+ * Alternative names for the command
1743
2039
  */
1744
- exitCode?: number;
2040
+ aliases?: string[];
1745
2041
  /**
1746
- * Indicates if the process is running
2042
+ * A description of the command
1747
2043
  */
1748
- running: boolean;
2044
+ description?: string;
1749
2045
  /**
1750
- * The data of the process
2046
+ * The author of the command
1751
2047
  */
1752
- data: any | undefined;
2048
+ author?: ICliCommandAuthor;
1753
2049
  /**
1754
- * Exit the process
1755
- * @param code The exit code
1756
- * @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.
1757
2055
  */
1758
- exit: (
2056
+ acceptsRawInput?: boolean;
1759
2057
  /**
1760
- * 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
1761
2074
  */
1762
- code?: number,
2075
+ valueRequired?: boolean;
1763
2076
  /**
1764
- * Options for exiting the process
2077
+ * The version of the command processor
2078
+ * @default '1.0.0'
1765
2079
  */
1766
- options?: {
1767
- /**
1768
- * Indicates if the exit should be silent, i.e. not throw an error
1769
- */
1770
- silent?: boolean;
1771
- }) => void;
2080
+ version?: string;
1772
2081
  /**
1773
- * Output data from the process
1774
- * @param data The data to output
2082
+ * The metadata for the command processor
1775
2083
  */
1776
- output(data: any): void;
1777
- }
1778
-
1779
- /**
1780
- * Represents a key-value store for the CLI
1781
- */
1782
- interface ICliKeyValueStore {
2084
+ metadata?: CliProcessorMetadata;
1783
2085
  /**
1784
- * Retrieves a value by key.
1785
- * @param key - The key to retrieve the value for.
1786
- * @returns A promise resolving to the value or undefined if not found.
2086
+ * Processors that are nested under this processor
1787
2087
  */
1788
- get<T = any>(key: string): Promise<T | undefined>;
2088
+ processors?: ICliCommandChildProcessor[];
1789
2089
  /**
1790
- * Sets a key-value pair in the store.
1791
- * @param key - The key to set.
1792
- * @param value - The value to store.
1793
- * @returns A promise resolving when the value is stored.
2090
+ * Parameters that the command accepts
1794
2091
  */
1795
- set(key: string, value: any): Promise<void>;
2092
+ parameters?: ICliCommandParameterDescriptor[];
1796
2093
  /**
1797
- * Removes a key-value pair by key.
1798
- * @param key - The key to remove.
1799
- * @returns A promise resolving when the key is removed.
2094
+ * Hooks that are executed before and after the command is processed
1800
2095
  */
1801
- remove(key: string): Promise<void>;
2096
+ hooks?: ICliProcessorHook[];
1802
2097
  /**
1803
- * Clears all key-value pairs from the store.
1804
- * @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
1805
2102
  */
1806
- clear(): Promise<void>;
1807
- }
1808
- /**
1809
- * Reactive state store scoped to a command processor or module.
1810
- *
1811
- * State is a plain object (`Record<string, any>`). Updates are shallow-merged
1812
- * (top-level keys are replaced, nested objects are not deep-merged).
1813
- * `getState()` returns a snapshot — mutating the returned object has no effect;
1814
- * always use `updateState()` to change state.
1815
- */
1816
- interface ICliStateStore {
2103
+ stateConfiguration?: CliStateConfiguration;
1817
2104
  /**
1818
- * Get a snapshot of the current state.
1819
- * @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.
1820
2108
  */
1821
- getState<T extends CliState = CliState>(): T;
2109
+ configurationOptions?: ICliConfigurationOption[];
1822
2110
  /**
1823
- * Shallow-merge new values into the current state.
1824
- * Only the provided keys are updated; other keys are preserved.
1825
- * Triggers subscribers and persists if a storage backend is configured.
1826
- * @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.
1827
2114
  */
1828
- updateState(newState: Partial<CliState>): void;
2115
+ extendsProcessor?: boolean;
1829
2116
  /**
1830
- * Select a specific property or computed value from the state.
1831
- * @param selector A function to project a slice of the state.
1832
- * @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.
1833
2120
  */
1834
- select<K>(selector: (state: CliState) => K): Observable<K>;
2121
+ originalProcessor?: ICliCommandProcessor;
1835
2122
  /**
1836
- * Subscribe to state changes.
1837
- * @param callback Callback function to handle state changes.
1838
- * @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
1839
2126
  */
1840
- subscribe(callback: (state: CliState) => void): Subscription;
2127
+ processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
1841
2128
  /**
1842
- * 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
1843
2131
  */
1844
- reset(): void;
2132
+ writeDescription?(context: ICliExecutionContext): void;
1845
2133
  /**
1846
- * 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
1847
2137
  */
1848
- persist(): Promise<void>;
2138
+ validateBeforeExecution?: (command: CliProcessCommand, context: ICliExecutionContext) => {
2139
+ valid: boolean;
2140
+ message?: string;
2141
+ };
1849
2142
  /**
1850
- * Initialize the state from storage.
2143
+ * Initialize the command processor
2144
+ * @param context The context in which the command is executed
1851
2145
  */
1852
- 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;
1853
2180
  }
1854
2181
 
1855
2182
  /**
@@ -1994,446 +2321,354 @@ interface ICliLogger {
1994
2321
  * Log a debug message (DEBUG level)
1995
2322
  * @param args The arguments to log
1996
2323
  */
1997
- debug(...args: any[]): void;
1998
- }
1999
-
2000
- /**
2001
- * Provides internationalization (i18n) support for CLI strings.
2002
- */
2003
- interface ICliTranslationService {
2004
- /**
2005
- * Translate a key to the current locale.
2006
- * @param key The translation key (e.g. 'cli.echo.description')
2007
- * @param defaultValue The English fallback string (returned if no translation found)
2008
- * @param params Optional interpolation parameters for `{param}` placeholders
2009
- */
2010
- t(key: string, defaultValue: string, params?: Record<string, string | number>): string;
2011
- /**
2012
- * Get the current locale code (e.g. 'en', 'es', 'fr').
2013
- */
2014
- getLocale(): string;
2015
- /**
2016
- * Set the active locale.
2017
- * @param locale The locale code to switch to
2018
- */
2019
- setLocale(locale: string): void;
2020
- /**
2021
- * Register translations for a locale.
2022
- * Can be called multiple times — translations are merged, with later calls overriding earlier ones.
2023
- * @param locale The locale code
2024
- * @param translations Flat key-value map of translation keys to translated strings
2025
- */
2026
- addTranslations(locale: string, translations: Record<string, string>): void;
2027
- /**
2028
- * Get all locale codes that have at least one registered translation.
2029
- */
2030
- getAvailableLocales(): string[];
2031
- }
2032
- /**
2033
- * Dependency injection container for CLI services.
2034
- * Services are registered with string tokens and retrieved by type.
2035
- */
2036
- interface ICliServiceProvider {
2037
- /**
2038
- * Retrieve a service by its injection token.
2039
- * @param service The token (typically a `*_TOKEN` constant) identifying the service
2040
- * @returns The service instance, cast to `T`
2041
- * @throws If no service is registered for the given token
2042
- */
2043
- get<T = unknown>(service: any): T;
2044
- /**
2045
- * Register one or more service definitions.
2046
- * @param definition A single provider or an array of providers to register
2047
- */
2048
- set(definition: CliProvider | CliProvider[]): void;
2049
- }
2050
-
2051
- /**
2052
- * Abstract permission service for checking rwx permissions on resources.
2053
- * The default implementation lives in @qodalis/cli-users; consumers can
2054
- * replace it via the DI container.
2055
- */
2056
- interface ICliPermissionService {
2057
- /**
2058
- * Check whether a user may perform an action on a resource.
2059
- * @param user The acting user.
2060
- * @param action The requested operation.
2061
- * @param ownership Owner/group of the resource.
2062
- * @param permissions Permission string (e.g. "rwxr-xr-x").
2063
- * @returns true if allowed.
2064
- */
2065
- check(user: ICliUser, action: 'read' | 'write' | 'execute', ownership: ICliOwnership, permissions: string): boolean;
2066
- /** Parse octal (e.g. "755") to a permission string (e.g. "rwxr-xr-x"). */
2067
- parseOctal(octal: string): string;
2068
- /** Convert a permission string (e.g. "rwxr-xr-x") to octal (e.g. "755"). */
2069
- toOctal(permissions: string): string;
2324
+ debug(...args: any[]): void;
2070
2325
  }
2071
2326
 
2072
2327
  /**
2073
- * Context passed to completion providers describing the current input state.
2074
- */
2075
- interface ICliCompletionContext {
2076
- /** Full current line text */
2077
- input: string;
2078
- /** Cursor position in the line */
2079
- cursor: number;
2080
- /** The token (word) being completed at the cursor position */
2081
- token: string;
2082
- /** Start index of the token in the input string */
2083
- tokenStart: number;
2084
- /** Index of the token among all tokens (0 = command, 1+ = arguments) */
2085
- tokenIndex: number;
2086
- /** All tokens parsed from the input */
2087
- tokens: string[];
2088
- }
2089
- /**
2090
- * Provides tab-completion candidates for CLI input.
2091
- * Plugins can register providers to extend completion (e.g. file paths, custom values).
2328
+ * Provides internationalization (i18n) support for CLI strings.
2092
2329
  */
2093
- interface ICliCompletionProvider {
2330
+ interface ICliTranslationService {
2094
2331
  /**
2095
- * Priority order. Lower values are checked first.
2096
- * Built-in defaults: 100 (commands), 200 (parameters).
2097
- * 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
2098
2336
  */
2099
- priority: number;
2337
+ t(key: string, defaultValue: string, params?: Record<string, string | number>): string;
2100
2338
  /**
2101
- * Return completion candidates for the current input context.
2102
- * Return an empty array if this provider does not apply.
2339
+ * Get the current locale code (e.g. 'en', 'es', 'fr').
2103
2340
  */
2104
- getCompletions(context: ICliCompletionContext): string[] | Promise<string[]>;
2105
- }
2106
-
2107
- interface ICliProgressBar {
2341
+ getLocale(): string;
2108
2342
  /**
2109
- * Indicates if the progress bar is running
2343
+ * Set the active locale.
2344
+ * @param locale The locale code to switch to
2110
2345
  */
2111
- isRunning: boolean;
2346
+ setLocale(locale: string): void;
2112
2347
  /**
2113
- * 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
2114
2352
  */
2115
- show: (text?: string) => void;
2353
+ addTranslations(locale: string, translations: Record<string, string>): void;
2116
2354
  /**
2117
- * Hide the progress bar
2355
+ * Get all locale codes that have at least one registered translation.
2118
2356
  */
2119
- hide: () => void;
2357
+ getAvailableLocales(): string[];
2120
2358
  }
2121
2359
  /**
2122
- * Represents a spinner for the CLI
2360
+ * Dependency injection container for CLI services.
2361
+ * Services are registered with string tokens and retrieved by type.
2123
2362
  */
2124
- interface ICliSpinner extends ICliProgressBar {
2363
+ interface ICliServiceProvider {
2125
2364
  /**
2126
- * Set the text of the spinner
2127
- * @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
2128
2370
  */
2129
- setText: (text: string) => void;
2130
- }
2131
- type CliPercentageProgressBarUpdateValueOptions = {
2371
+ get<T = unknown>(service: any): T | undefined;
2132
2372
  /**
2133
- * The type of update to perform
2134
- * @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
2135
2377
  */
2136
- type?: 'replace' | 'increment';
2137
- };
2138
- /**
2139
- * Represents a progress bar for the CLI
2140
- */
2141
- interface ICliPercentageProgressBar extends ICliProgressBar {
2378
+ getAll<T = unknown>(service: any): T[];
2142
2379
  /**
2143
- * Update the progress of the progress bar.
2144
- * @param progress The progress value (0–100). Values outside this range are clamped.
2145
- * @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
2146
2386
  */
2147
- update: (progress: number, options?: CliPercentageProgressBarUpdateValueOptions) => void;
2387
+ getRequired<T = unknown>(service: any): T;
2148
2388
  /**
2149
- * Complete the progress bar
2150
- * @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
2151
2392
  */
2152
- complete: () => void;
2393
+ has(service: any): boolean;
2153
2394
  /**
2154
- * Set the text of the spinner
2155
- * @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
2156
2397
  */
2157
- setText: (text: string) => void;
2398
+ set(definition: CliProvider | CliProvider[]): void;
2158
2399
  }
2159
- type CliTextAnimatorOptions = {
2160
- /**
2161
- * The speed of the animation
2162
- * @default 100
2163
- */
2164
- 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 {
2165
2430
  /**
2166
- * 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
2167
2436
  */
2168
- removeAfterTyping?: boolean;
2169
- };
2170
- 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 {
2171
2447
  /**
2172
- * Show animated text in a typing and erasing effect.
2173
- * @param text The text to animate
2174
- * @param options Optional: speed (ms per character), removeAfterTyping
2175
- * @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
2176
2454
  */
2177
- showText: (text: string, options?: CliTextAnimatorOptions) => Promise<void>;
2455
+ getHeaders(serverName: string, configHeaders?: CliHeadersProvider): Record<string, string>;
2178
2456
  }
2179
2457
 
2180
2458
  /**
2181
- * 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()}` })
2182
2469
  */
2183
- interface ICliUserSessionService {
2184
- /** Gets the current user session as a reactive stream */
2185
- getUserSession(): Observable<ICliUserSession | undefined>;
2186
- /** Sets the current user session */
2187
- setUserSession(session: ICliUserSession): Promise<void>;
2188
- /** Clears the current session (logout) */
2189
- clearSession(): Promise<void>;
2190
- /** Persists the current session to storage */
2191
- persistSession(): Promise<void>;
2192
- /** Restores a session from storage (called on boot) */
2193
- restoreSession(): Promise<ICliUserSession | undefined>;
2194
- }
2470
+ type CliHeadersProvider = Record<string, string> | (() => Record<string, string>);
2195
2471
  /**
2196
- * Represents a service that manages users in the CLI
2472
+ * Resolves a CliHeadersProvider to a plain header map.
2197
2473
  */
2198
- interface ICliUsersStoreService {
2199
- /** Gets users with optional filtering and pagination */
2200
- getUsers(options?: {
2201
- query?: string;
2202
- skip?: number;
2203
- take?: number;
2204
- }): Observable<ICliUser[]>;
2205
- /** Creates a new user */
2206
- createUser(user: CliAddUser): Promise<ICliUser>;
2207
- /** Gets a user by id, name, or email */
2208
- getUser(id: string): Observable<ICliUser | undefined>;
2209
- /** Updates an existing user */
2210
- updateUser(id: string, updates: CliUpdateUser): Promise<ICliUser>;
2211
- /** Deletes a user by id */
2212
- deleteUser(id: string): Promise<void>;
2213
- }
2474
+ declare function resolveHeaders(provider?: CliHeadersProvider): Record<string, string>;
2214
2475
  /**
2215
- * 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
2216
2485
  */
2217
- interface ICliGroupsStoreService {
2218
- /** Gets all groups */
2219
- getGroups(): Observable<ICliGroup[]>;
2220
- /** Gets a group by id or name */
2221
- getGroup(id: string): Observable<ICliGroup | undefined>;
2222
- /** Creates a new group */
2223
- createGroup(name: string, description?: string): Promise<ICliGroup>;
2224
- /** Deletes a group by id */
2225
- deleteGroup(id: string): Promise<void>;
2226
- /** Gets all users that belong to a group */
2227
- getGroupMembers(groupId: string): Observable<ICliUser[]>;
2228
- }
2486
+ declare function resolveServerHeaders(services: ICliServiceProvider | undefined, serverName: string, configHeaders?: CliHeadersProvider): Record<string, string>;
2229
2487
  /**
2230
- * Represents a service that handles authentication in the CLI
2488
+ * Configuration for a remote CLI server
2231
2489
  */
2232
- interface ICliAuthService {
2233
- /** Authenticates a user and returns a session */
2234
- login(username: string, password: string): Promise<ICliUserSession>;
2235
- /** Ends the current session */
2236
- logout(): Promise<void>;
2237
- /** Sets or updates a user's password */
2238
- setPassword(userId: string, password: string): Promise<void>;
2239
- /** Verifies a password against stored credentials */
2240
- verifyPassword(userId: string, password: string): Promise<boolean>;
2241
- /** Hashes a password with a salt using Web Crypto SHA-256 */
2242
- hashPassword(password: string, salt: string): Promise<string>;
2243
- }
2244
-
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
+ };
2245
2506
  /**
2246
- * Represents a serialized snapshot of a CLI engine's state.
2247
- * Used to duplicate terminal tabs with full state preservation.
2507
+ * A single output item in a server response
2248
2508
  */
2249
- interface CliEngineSnapshot {
2250
- /** Schema version for forward compatibility */
2251
- version: 1;
2252
- /** Timestamp (ms since epoch) when the snapshot was taken */
2253
- timestamp: number;
2254
- /** Serialized terminal state */
2255
- terminal: {
2256
- /** Terminal buffer serialized via @xterm/addon-serialize */
2257
- serializedBuffer: string;
2258
- /** Terminal column count at time of snapshot */
2259
- cols: number;
2260
- /** Terminal row count at time of snapshot */
2261
- rows: number;
2262
- };
2263
- /** Command history entries (most recent last) */
2264
- commandHistory: string[];
2265
- /** Named state store entries */
2266
- stateStores: Array<{
2267
- name: string;
2268
- state: Record<string, any>;
2269
- }>;
2270
- }
2271
-
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
+ };
2272
2538
  /**
2273
- * Messages sent from the main thread to a background service Worker.
2539
+ * Metadata about a remote command processor, returned by GET /api/qcli/commands
2274
2540
  */
2275
- type CliWorkerInboundMessage = {
2276
- type: 'start';
2277
- config?: Record<string, unknown>;
2278
- } | {
2279
- type: 'stop';
2280
- } | {
2281
- 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[];
2282
2554
  };
2283
2555
  /**
2284
- * Messages sent from a background service Worker to the main thread.
2556
+ * Server capabilities returned by GET /api/qcli/capabilities
2285
2557
  */
2286
- type CliWorkerOutboundMessage = {
2287
- type: 'log';
2288
- level: 'info' | 'warn' | 'error';
2289
- message: string;
2290
- } | {
2291
- type: 'event';
2292
- event: Omit<ICliServiceEvent, 'timestamp'>;
2293
- } | {
2294
- type: 'state-update';
2295
- patch: Record<string, unknown>;
2296
- } | {
2297
- type: 'status';
2298
- status: CliBackgroundServiceStatus;
2299
- } | {
2300
- type: 'error';
2301
- message: string;
2302
- 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;
2303
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>;
2304
2598
 
2305
2599
  /**
2306
- * Represents an entry in a file listing.
2600
+ * Represents a user in the CLI
2307
2601
  */
2308
- interface ICliFileEntry {
2602
+ interface ICliUser {
2603
+ /** Unique user identifier */
2604
+ id: string;
2605
+ /** Login name (unique) */
2309
2606
  name: string;
2310
- type: 'file' | 'directory';
2311
- size: number;
2312
- 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;
2313
2619
  }
2314
-
2315
2620
  /**
2316
- * Abstraction for file transfer operations.
2317
- * Default implementation uses browser-native APIs (file picker, download dialog).
2318
- * @qodalis/cli-files overrides with virtual FS backed by IndexedDB.
2621
+ * Represents user credentials (shadow pattern — stored separately from ICliUser)
2319
2622
  */
2320
- interface ICliFileTransferService {
2321
- readFile(path: string): Promise<string | null>;
2322
- writeFile(path: string, content: string): Promise<void>;
2323
- listFiles(path: string): Promise<ICliFileEntry[]>;
2324
- exists(path: string): Promise<boolean>;
2325
- downloadToBrowser(filename: string, content: string | Blob): void;
2326
- uploadFromBrowser(accept?: string): Promise<{
2327
- name: string;
2328
- content: string;
2329
- } | null>;
2330
- }
2331
-
2332
- interface ICliDragDropService {
2333
- /** Emits an array of dropped File objects each time files are dropped onto the terminal */
2334
- 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;
2335
2632
  }
2336
-
2337
2633
  /**
2338
- * Opaque state value carried between lines during syntax highlighting.
2339
- * Encodes context such as "inside a multi-line string" or "inside a block comment"
2340
- * so the highlighter can resume correctly on the next line.
2341
- * `0` typically represents the default/root state.
2634
+ * Represents a group in the CLI
2342
2635
  */
2343
- type LineState = number;
2344
- interface ISyntaxHighlightRule {
2345
- pattern: RegExp;
2346
- tokenType: string;
2347
- captureGroup?: number;
2348
- }
2349
- interface ISyntaxHighlighter {
2636
+ interface ICliGroup {
2637
+ /** Unique group identifier */
2350
2638
  id: string;
2351
- /** Human-readable language name (e.g. 'TypeScript'). Falls back to `id` when absent. */
2352
- name?: string;
2353
- extensions: string[];
2354
- initialState: LineState;
2355
- getRules(state: LineState): ISyntaxHighlightRule[];
2356
- getNextLineState(line: string, currentState: LineState): LineState;
2357
- }
2358
- interface ISyntaxTheme {
2639
+ /** Group name (unique) */
2359
2640
  name: string;
2360
- colors: Record<string, string>;
2641
+ /** Optional group description */
2642
+ description?: string;
2643
+ /** Group creation timestamp */
2644
+ createdAt: number;
2361
2645
  }
2362
-
2363
2646
  /**
2364
- * Framework-agnostic interface for programmatic control of the CLI panel.
2365
- *
2366
- * CliEngine is referenced as a generic to avoid a circular dependency
2367
- * between @qodalis/cli-core and @qodalis/cli. Framework implementations
2368
- * resolve this to the concrete CliEngine class.
2647
+ * Represents an active user session
2369
2648
  */
2370
- interface ICliPanelRef<TEngine = unknown> {
2371
- /** Expand the panel (sets collapsed=false). Initializes the first tab on first call. */
2372
- open(): void;
2373
- /** Collapse the panel body (sets collapsed=true). */
2374
- collapse(): void;
2375
- toggleCollapse(): void;
2376
- /** Hide the panel to a small viewport-edge tab (reversible via unhide). */
2377
- hide(): void;
2378
- unhide(): void;
2379
- toggleHide(): void;
2380
- /** Destroy the panel (removes from DOM). Irreversible. */
2381
- close(): void;
2382
- maximize(): void;
2383
- restore(): void;
2384
- toggleMaximize(): void;
2385
- /**
2386
- * Set panel dimensions. Only the dimension relevant to the current
2387
- * position is applied immediately (height for top/bottom, width for
2388
- * left/right). The other dimension is stored for when the position changes.
2389
- */
2390
- resize(dimensions: {
2391
- height?: number;
2392
- width?: number;
2393
- }): void;
2394
- setPosition(position: CliPanelPosition): void;
2395
- /** Create a new tab. Returns the new tab's ID. Title defaults to "Terminal {id}". */
2396
- addTab(title?: string): number;
2397
- /** Close a tab by ID. No-op if the ID does not exist. */
2398
- closeTab(tabId: number): void;
2399
- /** Activate a tab by ID. No-op if the ID does not exist. */
2400
- selectTab(tabId: number): void;
2401
- /** Programmatically rename a tab. No-op if the ID does not exist. */
2402
- renameTab(tabId: number, title: string): void;
2403
- /**
2404
- * Split the active pane (or a pane within the specified tab) to create
2405
- * a new pane to the right. Returns the new pane's ID.
2406
- */
2407
- splitPane(tabId?: number): number;
2408
- /**
2409
- * Close a pane by ID. Searches all tabs for the pane.
2410
- * No-op if the ID does not exist.
2411
- */
2412
- closePane(paneId: number): void;
2413
- /** Get the engine for a specific pane, or the active pane if omitted. */
2414
- getEngine(paneId?: number): TEngine | undefined;
2415
- getState(): CliPanelState;
2416
- }
2417
- interface CliPanelState {
2418
- collapsed: boolean;
2419
- hidden: boolean;
2420
- maximized: boolean;
2421
- position: CliPanelPosition;
2422
- height: number;
2423
- width: number;
2424
- activeTabId: number;
2425
- activePaneId: number;
2426
- tabs: CliPanelTabState[];
2427
- }
2428
- interface CliPanelTabState {
2429
- id: number;
2430
- title: string;
2431
- panes: CliPanelPaneState[];
2432
- }
2433
- interface CliPanelPaneState {
2434
- id: number;
2435
- 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>;
2436
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
+ };
2437
2672
 
2438
2673
  /**
2439
2674
  * Registry that tracks loaded web CLI modules (frontend plugins) and dispatches
@@ -2597,12 +2832,36 @@ declare class ServerVersionNegotiator {
2597
2832
  * Returns the negotiated API version and the base path for all subsequent calls,
2598
2833
  * or null if the server is unreachable or incompatible.
2599
2834
  */
2600
- static discover(baseUrl: string): Promise<{
2835
+ static discover(baseUrl: string, headers?: CliHeadersProvider): Promise<{
2601
2836
  apiVersion: number;
2602
2837
  basePath: string;
2603
2838
  } | null>;
2604
2839
  }
2605
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
+
2606
2865
  /**
2607
2866
  * Derives CLI panel CSS custom property values from an xterm ITheme object.
2608
2867
  * Used when `syncTheme` is enabled on the panel config.
@@ -2643,10 +2902,11 @@ declare function nextPanelPosition(current: CliPanelPosition): CliPanelPosition;
2643
2902
  */
2644
2903
  declare function stripAnsi(text: string): string;
2645
2904
  /**
2646
- * Return the visible length of a string, ignoring ANSI escape codes.
2647
- * 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.
2648
2908
  * @param text The text potentially containing ANSI codes
2649
- * @returns The number of visible characters
2909
+ * @returns The number of terminal columns the text occupies
2650
2910
  */
2651
2911
  declare function visibleLength(text: string): number;
2652
2912
 
@@ -2802,7 +3062,7 @@ interface CliThemeInfo {
2802
3062
 
2803
3063
  declare const DefaultThemeInfos: Record<string, CliThemeInfo>;
2804
3064
 
2805
- declare const LIBRARY_VERSION = "2.0.0-beta.12";
3065
+ declare const LIBRARY_VERSION = "2.0.0-beta.13";
2806
3066
  declare const API_VERSION = 2;
2807
3067
 
2808
3068
  /**
@@ -2863,4 +3123,4 @@ declare class BrowserFileTransferService implements ICliFileTransferService {
2863
3123
  private _pickFile;
2864
3124
  }
2865
3125
 
2866
- 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 };