@qodalis/cli-core 0.0.16 → 2.0.0-beta.10
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/README.md +610 -38
- package/package.json +16 -23
- package/public-api.d.mts +2771 -0
- package/public-api.d.ts +2771 -8
- package/public-api.js +3692 -0
- package/public-api.js.map +1 -0
- package/public-api.mjs +3635 -0
- package/public-api.mjs.map +1 -0
- package/esm2022/lib/constants/index.mjs +0 -8
- package/esm2022/lib/interfaces/command-hooks.mjs +0 -2
- package/esm2022/lib/interfaces/command-processor.mjs +0 -2
- package/esm2022/lib/interfaces/execution-context.mjs +0 -2
- package/esm2022/lib/interfaces/index.mjs +0 -6
- package/esm2022/lib/interfaces/progress-bars.mjs +0 -2
- package/esm2022/lib/interfaces/users.mjs +0 -2
- package/esm2022/lib/models/index.mjs +0 -175
- package/esm2022/lib/models/services.mjs +0 -2
- package/esm2022/lib/models/users.mjs +0 -2
- package/esm2022/lib/modules/index.mjs +0 -30
- package/esm2022/lib/themes/index.mjs +0 -221
- package/esm2022/lib/types/CancellablePromise.mjs +0 -28
- package/esm2022/lib/types/index.mjs +0 -2
- package/esm2022/lib/utils/delay.mjs +0 -4
- package/esm2022/lib/utils/index.mjs +0 -81
- package/esm2022/lib/utils/object-describer.mjs +0 -134
- package/esm2022/lib/utils/terminal-utils.mjs +0 -16
- package/esm2022/lib/utils/version-utils.mjs +0 -25
- package/esm2022/lib/version.mjs +0 -3
- package/esm2022/public-api.mjs +0 -12
- package/esm2022/qodalis-cli-core.mjs +0 -5
- package/fesm2022/qodalis-cli-core.mjs +0 -722
- package/fesm2022/qodalis-cli-core.mjs.map +0 -1
- package/index.d.ts +0 -5
- package/lib/constants/index.d.ts +0 -5
- package/lib/interfaces/command-hooks.d.ts +0 -5
- package/lib/interfaces/command-processor.d.ts +0 -151
- package/lib/interfaces/execution-context.d.ts +0 -109
- package/lib/interfaces/index.d.ts +0 -349
- package/lib/interfaces/progress-bars.d.ts +0 -72
- package/lib/interfaces/users.d.ts +0 -42
- package/lib/models/index.d.ts +0 -303
- package/lib/models/services.d.ts +0 -20
- package/lib/models/users.d.ts +0 -30
- package/lib/modules/index.d.ts +0 -6
- package/lib/themes/index.d.ts +0 -16
- package/lib/types/CancellablePromise.d.ts +0 -8
- package/lib/types/index.d.ts +0 -1
- package/lib/utils/delay.d.ts +0 -1
- package/lib/utils/index.d.ts +0 -25
- package/lib/utils/object-describer.d.ts +0 -12
- package/lib/utils/terminal-utils.d.ts +0 -7
- package/lib/utils/version-utils.d.ts +0 -9
- package/lib/version.d.ts +0 -1
package/README.md
CHANGED
|
@@ -1,34 +1,56 @@
|
|
|
1
|
-
<h1 align="center">Qodalis
|
|
1
|
+
<h1 align="center">Qodalis Web CLI</h1>
|
|
2
2
|
|
|
3
|
-
<p align="center">A web-based terminal for Angular
|
|
3
|
+
<p align="center">A web-based terminal for Angular, React, and Vue — extensible, themeable, and packed with built-in developer tools.</p>
|
|
4
4
|
|
|
5
5
|
<div align="center">
|
|
6
6
|
|
|
7
|
-
[](https://www.npmjs.com/package/@qodalis/cli)
|
|
8
|
+
[](https://www.npmjs.com/package/@qodalis/angular-cli)
|
|
9
|
+
[](https://www.npmjs.com/package/@qodalis/react-cli)
|
|
10
|
+
[](https://www.npmjs.com/package/@qodalis/vue-cli)
|
|
11
|
+
[](https://github.com/qodalis-solutions/web-cli/actions)
|
|
9
12
|
[](https://opensource.org/licenses/MIT)
|
|
10
13
|
|
|
11
14
|
</div>
|
|
12
15
|
|
|
13
16
|
<p align="center">
|
|
14
|
-
<a href="https://cli
|
|
15
|
-
<a href="https://
|
|
16
|
-
<a href="https://www.npmjs.com/package/@qodalis/
|
|
17
|
+
<a href="https://cli.qodalis.com/">Live Demo</a> ·
|
|
18
|
+
<a href="https://cli.qodalis.com/docs/">Documentation</a> ·
|
|
19
|
+
<a href="https://www.npmjs.com/package/@qodalis/cli">npm</a>
|
|
17
20
|
</p>
|
|
18
21
|
|
|
19
22
|
---
|
|
20
23
|
|
|
24
|
+
## Try It Online
|
|
25
|
+
|
|
26
|
+
| Framework | StackBlitz | CodeSandbox | Gitpod |
|
|
27
|
+
|-----------|------------|-------------|--------|
|
|
28
|
+
| **Angular** | [](https://stackblitz.com/github/qodalis-solutions/qodalis-cli-angular-example) | [](https://codesandbox.io/p/github/qodalis-solutions/qodalis-cli-angular-example) | [](https://gitpod.io/#https://github.com/qodalis-solutions/qodalis-cli-angular-example) |
|
|
29
|
+
| **React** | [](https://stackblitz.com/github/qodalis-solutions/qodalis-cli-react-example) | [](https://codesandbox.io/p/github/qodalis-solutions/qodalis-cli-react-example) | [](https://gitpod.io/#https://github.com/qodalis-solutions/qodalis-cli-react-example) |
|
|
30
|
+
| **Vue** | [](https://stackblitz.com/github/qodalis-solutions/qodalis-cli-vue-example) | [](https://codesandbox.io/p/github/qodalis-solutions/qodalis-cli-vue-example) | [](https://gitpod.io/#https://github.com/qodalis-solutions/qodalis-cli-vue-example) |
|
|
31
|
+
| **Vanilla** | [](https://stackblitz.com/github/qodalis-solutions/qodalis-cli-vanilla-example) | [](https://codesandbox.io/p/github/qodalis-solutions/qodalis-cli-vanilla-example) | [](https://gitpod.io/#https://github.com/qodalis-solutions/qodalis-cli-vanilla-example) |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
21
35
|

|
|
22
36
|
|
|
23
|
-
##
|
|
37
|
+
## Packages
|
|
24
38
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
| Package | Description |
|
|
40
|
+
|---------|-------------|
|
|
41
|
+
| [`@qodalis/cli-core`](https://www.npmjs.com/package/@qodalis/cli-core) | Shared interfaces, models, and types |
|
|
42
|
+
| [`@qodalis/cli`](https://www.npmjs.com/package/@qodalis/cli) | Framework-agnostic terminal engine (50+ built-in commands) |
|
|
43
|
+
| [`@qodalis/angular-cli`](https://www.npmjs.com/package/@qodalis/angular-cli) | Angular wrapper |
|
|
44
|
+
| [`@qodalis/react-cli`](https://www.npmjs.com/package/@qodalis/react-cli) | React wrapper |
|
|
45
|
+
| [`@qodalis/vue-cli`](https://www.npmjs.com/package/@qodalis/vue-cli) | Vue 3 wrapper |
|
|
28
46
|
|
|
29
47
|
## Quick Start
|
|
30
48
|
|
|
31
|
-
|
|
49
|
+
### Angular
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install @qodalis/angular-cli
|
|
53
|
+
```
|
|
32
54
|
|
|
33
55
|
```typescript
|
|
34
56
|
import { CliModule } from '@qodalis/angular-cli';
|
|
@@ -39,30 +61,62 @@ import { CliModule } from '@qodalis/angular-cli';
|
|
|
39
61
|
export class AppModule {}
|
|
40
62
|
```
|
|
41
63
|
|
|
42
|
-
|
|
64
|
+
Add styles to `angular.json`:
|
|
43
65
|
|
|
44
66
|
```json
|
|
45
67
|
{
|
|
46
68
|
"styles": [
|
|
47
|
-
"node_modules/@qodalis/angular-cli/src/assets/styles.
|
|
69
|
+
"node_modules/@qodalis/angular-cli/src/assets/styles.css"
|
|
48
70
|
]
|
|
49
71
|
}
|
|
50
72
|
```
|
|
51
73
|
|
|
52
|
-
**3. Add the terminal to your template:**
|
|
53
|
-
|
|
54
74
|
```html
|
|
55
75
|
<!-- Full terminal -->
|
|
56
76
|
<cli [options]="cliOptions" />
|
|
57
77
|
|
|
58
|
-
<!-- Collapsible panel
|
|
78
|
+
<!-- Collapsible panel -->
|
|
59
79
|
<cli-panel />
|
|
60
80
|
```
|
|
61
81
|
|
|
62
|
-
|
|
82
|
+
### React
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm install @qodalis/react-cli
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import '@qodalis/react-cli/styles.css';
|
|
90
|
+
import { Cli } from '@qodalis/react-cli';
|
|
91
|
+
|
|
92
|
+
function App() {
|
|
93
|
+
return <Cli style={{ width: '100vw', height: '100vh' }} />;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Vue
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install @qodalis/vue-cli
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```vue
|
|
104
|
+
<script setup lang="ts">
|
|
105
|
+
import '@qodalis/vue-cli/styles.css';
|
|
106
|
+
import { Cli } from '@qodalis/vue-cli';
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<template>
|
|
110
|
+
<Cli :style="{ width: '100vw', height: '100vh' }" />
|
|
111
|
+
</template>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Configuration (all frameworks)
|
|
115
|
+
|
|
116
|
+
Pass options to customize the terminal:
|
|
63
117
|
|
|
64
118
|
```typescript
|
|
65
|
-
|
|
119
|
+
const options = {
|
|
66
120
|
welcomeMessage: {
|
|
67
121
|
message: '-- your custom welcome message --',
|
|
68
122
|
show: 'daily', // 'never', 'once', 'daily', 'always'
|
|
@@ -83,7 +137,7 @@ cliOptions = {
|
|
|
83
137
|
| `version` | `ver` | Display CLI version and documentation link |
|
|
84
138
|
| `hotkeys` | `shortcuts`, `keys` | Show keyboard shortcuts |
|
|
85
139
|
| `history` | `hist` | Browse and clear command history |
|
|
86
|
-
| `theme` | `themes` | Apply, customize, and save terminal themes |
|
|
140
|
+
| `theme` | `themes` | Apply, customize, and save terminal themes (interactive selection with live preview) |
|
|
87
141
|
| `feedback` | `support` | Report bugs or request features on GitHub |
|
|
88
142
|
| `pkg` | `packages` | Install, update, remove, and browse packages |
|
|
89
143
|
|
|
@@ -145,23 +199,66 @@ pkg update # Update all packages
|
|
|
145
199
|
pkg update guid@1.0.2 # Pin a specific version
|
|
146
200
|
pkg check # Check for updates
|
|
147
201
|
pkg versions guid # Show all published versions
|
|
202
|
+
pkg source set # Interactively select a package source (CDN)
|
|
203
|
+
pkg source set unpkg # Set package source directly
|
|
148
204
|
```
|
|
149
205
|
|
|
150
206
|
### Available Packages
|
|
151
207
|
|
|
208
|
+
#### Utility Plugins
|
|
209
|
+
|
|
152
210
|
| Package | Command | Description |
|
|
153
211
|
|---------|---------|-------------|
|
|
212
|
+
| [@qodalis/cli-data-explorer](https://www.npmjs.com/package/@qodalis/cli-data-explorer) | `data-explorer` | Interactive query console for SQL, MongoDB, Redis, Elasticsearch |
|
|
154
213
|
| [@qodalis/cli-guid](https://www.npmjs.com/package/@qodalis/cli-guid) | `guid` | Generate and validate UUIDs |
|
|
155
|
-
| [@qodalis/cli-string](https://www.npmjs.com/package/@qodalis/cli-string) | `string` | String manipulation (case, trim, reverse, slug, wc, etc.) |
|
|
156
|
-
| [@qodalis/cli-curl](https://www.npmjs.com/package/@qodalis/cli-curl) | `curl` | HTTP requests (GET, POST, PUT, DELETE) |
|
|
157
|
-
| [@qodalis/cli-todo](https://www.npmjs.com/package/@qodalis/cli-todo) | `todo` | Task management |
|
|
158
214
|
| [@qodalis/cli-regex](https://www.npmjs.com/package/@qodalis/cli-regex) | `regex` | Regular expression testing |
|
|
159
215
|
| [@qodalis/cli-qr](https://www.npmjs.com/package/@qodalis/cli-qr) | `qr` | QR code generation |
|
|
160
216
|
| [@qodalis/cli-speed-test](https://www.npmjs.com/package/@qodalis/cli-speed-test) | `speed-test` | Internet speed test |
|
|
161
|
-
| [@qodalis/cli-
|
|
217
|
+
| [@qodalis/cli-curl](https://www.npmjs.com/package/@qodalis/cli-curl) | `curl` | HTTP requests (GET, POST, PUT, DELETE) |
|
|
218
|
+
| [@qodalis/cli-password-generator](https://www.npmjs.com/package/@qodalis/cli-password-generator) | `generate-password` | Password generation |
|
|
219
|
+
| [@qodalis/cli-string](https://www.npmjs.com/package/@qodalis/cli-string) | `string` | String manipulation (case, trim, reverse, slug, wc, etc.) |
|
|
220
|
+
| [@qodalis/cli-todo](https://www.npmjs.com/package/@qodalis/cli-todo) | `todo` | Task management |
|
|
162
221
|
| [@qodalis/cli-browser-storage](https://www.npmjs.com/package/@qodalis/cli-browser-storage) | `local-storage`, `cookies` | Browser storage operations |
|
|
163
222
|
| [@qodalis/cli-text-to-image](https://www.npmjs.com/package/@qodalis/cli-text-to-image) | `text-to-image` | Generate images from text |
|
|
164
|
-
| [@qodalis/cli-
|
|
223
|
+
| [@qodalis/cli-files](https://www.npmjs.com/package/@qodalis/cli-files) | `ls`, `cat`, `nano`, `mkdir`, `touch`, `rm` | Virtual filesystem |
|
|
224
|
+
| [@qodalis/cli-yesno](https://www.npmjs.com/package/@qodalis/cli-yesno) | `yesno` | Interactive yes/no confirmation prompts |
|
|
225
|
+
| [@qodalis/cli-server-logs](https://www.npmjs.com/package/@qodalis/cli-server-logs) | `server logs` | Live server log streaming with level filtering |
|
|
226
|
+
| [@qodalis/cli-server-jobs](https://www.npmjs.com/package/@qodalis/cli-server-jobs) | `server jobs` | Manage server-side background jobs |
|
|
227
|
+
| [@qodalis/cli-users](https://www.npmjs.com/package/@qodalis/cli-users) | `whoami`, `adduser`, `login` | User management and authentication |
|
|
228
|
+
| [@qodalis/cli-chart](https://www.npmjs.com/package/@qodalis/cli-chart) | `chart` | Render bar, line, and sparkline charts |
|
|
229
|
+
| [@qodalis/cli-cron](https://www.npmjs.com/package/@qodalis/cli-cron) | `cron` | Schedule and manage recurring commands |
|
|
230
|
+
| [@qodalis/cli-csv](https://www.npmjs.com/package/@qodalis/cli-csv) | `csv` | Parse, filter, sort, and convert CSV data |
|
|
231
|
+
| [@qodalis/cli-markdown](https://www.npmjs.com/package/@qodalis/cli-markdown) | `md` | Render Markdown content in the terminal |
|
|
232
|
+
| [@qodalis/cli-encode](https://www.npmjs.com/package/@qodalis/cli-encode) | `base64`, `url`, `hex`, `html` | Encode/decode Base64, URL, hex, HTML entities |
|
|
233
|
+
| [@qodalis/cli-scp](https://www.npmjs.com/package/@qodalis/cli-scp) | `scp` | Secure copy — transfer files between local and remote |
|
|
234
|
+
| [@qodalis/cli-wget](https://www.npmjs.com/package/@qodalis/cli-wget) | `wget` | Download files from URLs |
|
|
235
|
+
| [@qodalis/cli-stopwatch](https://www.npmjs.com/package/@qodalis/cli-stopwatch) | `stopwatch` | Interactive stopwatch and countdown timer |
|
|
236
|
+
|
|
237
|
+
#### Game Plugins
|
|
238
|
+
|
|
239
|
+
| Package | Command | Description |
|
|
240
|
+
|---------|---------|-------------|
|
|
241
|
+
| [@qodalis/cli-snake](https://www.npmjs.com/package/@qodalis/cli-snake) | `snake` | Classic Snake game |
|
|
242
|
+
| [@qodalis/cli-tetris](https://www.npmjs.com/package/@qodalis/cli-tetris) | `tetris` | Tetris |
|
|
243
|
+
| [@qodalis/cli-2048](https://www.npmjs.com/package/@qodalis/cli-2048) | `2048` | 2048 sliding puzzle |
|
|
244
|
+
| [@qodalis/cli-minesweeper](https://www.npmjs.com/package/@qodalis/cli-minesweeper) | `minesweeper` | Minesweeper |
|
|
245
|
+
| [@qodalis/cli-wordle](https://www.npmjs.com/package/@qodalis/cli-wordle) | `wordle` | Wordle word game |
|
|
246
|
+
| [@qodalis/cli-sudoku](https://www.npmjs.com/package/@qodalis/cli-sudoku) | `sudoku` | Sudoku puzzle |
|
|
247
|
+
|
|
248
|
+
#### Language Packs
|
|
249
|
+
|
|
250
|
+
| Package | Language |
|
|
251
|
+
|---------|----------|
|
|
252
|
+
| [@qodalis/cli-lang-es](https://www.npmjs.com/package/@qodalis/cli-lang-es) | Spanish |
|
|
253
|
+
| [@qodalis/cli-lang-fr](https://www.npmjs.com/package/@qodalis/cli-lang-fr) | French |
|
|
254
|
+
| [@qodalis/cli-lang-de](https://www.npmjs.com/package/@qodalis/cli-lang-de) | German |
|
|
255
|
+
| [@qodalis/cli-lang-it](https://www.npmjs.com/package/@qodalis/cli-lang-it) | Italian |
|
|
256
|
+
| [@qodalis/cli-lang-pt](https://www.npmjs.com/package/@qodalis/cli-lang-pt) | Portuguese |
|
|
257
|
+
| [@qodalis/cli-lang-ro](https://www.npmjs.com/package/@qodalis/cli-lang-ro) | Romanian |
|
|
258
|
+
| [@qodalis/cli-lang-ru](https://www.npmjs.com/package/@qodalis/cli-lang-ru) | Russian |
|
|
259
|
+
| [@qodalis/cli-lang-zh](https://www.npmjs.com/package/@qodalis/cli-lang-zh) | Chinese |
|
|
260
|
+
| [@qodalis/cli-lang-ja](https://www.npmjs.com/package/@qodalis/cli-lang-ja) | Japanese |
|
|
261
|
+
| [@qodalis/cli-lang-ko](https://www.npmjs.com/package/@qodalis/cli-lang-ko) | Korean |
|
|
165
262
|
|
|
166
263
|
Any npm package with UMD support can also be loaded:
|
|
167
264
|
|
|
@@ -170,9 +267,463 @@ pkg add lodash
|
|
|
170
267
|
eval _.map([1, 2, 3], n => n * 2)
|
|
171
268
|
```
|
|
172
269
|
|
|
173
|
-
##
|
|
270
|
+
## Server Integration
|
|
174
271
|
|
|
175
|
-
|
|
272
|
+
Connect the frontend terminal to a backend server for server-side command execution, interactive shell sessions, filesystem access, and event streaming. Three official backend implementations are available:
|
|
273
|
+
|
|
274
|
+
| Server | Package | Port | Tech Stack |
|
|
275
|
+
|--------|---------|------|------------|
|
|
276
|
+
| **.NET** | [Qodalis.Cli](https://www.nuget.org/packages/Qodalis.Cli) | 8046 | ASP.NET Core, .NET 8 |
|
|
277
|
+
| **Node.js** | [@qodalis/cli-server](https://www.npmjs.com/package/@qodalis/cli-server) | 8047 | Express, TypeScript, node-pty |
|
|
278
|
+
| **Python** | [qodalis-cli-server](https://pypi.org/project/qodalis-cli-server/) | 8048 | FastAPI, uvicorn |
|
|
279
|
+
|
|
280
|
+
All three implement the same API surface:
|
|
281
|
+
|
|
282
|
+
| Endpoint | Method | Purpose |
|
|
283
|
+
|----------|--------|---------|
|
|
284
|
+
| `/api/cli/versions` | GET | Version discovery |
|
|
285
|
+
| `/api/v1/cli/commands` | GET | List registered command processors |
|
|
286
|
+
| `/api/v1/cli/execute` | POST | Execute a CLI command |
|
|
287
|
+
| `/api/v1/cli/execute/stream` | POST | Execute with SSE streaming output |
|
|
288
|
+
| `/ws/v1/cli/events` | WS | Server-push event streaming |
|
|
289
|
+
| `/ws/v1/cli/shell` | WS | Interactive PTY shell session |
|
|
290
|
+
| `/api/cli/fs/*` | Various | Filesystem operations (ls, cat, upload, download, mkdir, rm) |
|
|
291
|
+
|
|
292
|
+
### Connecting to a Server
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { CliOptions } from '@qodalis/cli-core';
|
|
296
|
+
|
|
297
|
+
const options: CliOptions = {
|
|
298
|
+
servers: [
|
|
299
|
+
{ name: 'node', url: 'http://localhost:8047' },
|
|
300
|
+
{ name: 'dotnet', url: 'http://localhost:8046' },
|
|
301
|
+
{ name: 'python', url: 'http://localhost:8048' },
|
|
302
|
+
],
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// Angular: <cli [options]="options" />
|
|
306
|
+
// React: <Cli options={options} />
|
|
307
|
+
// Vue: <Cli :options="options" />
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### SSE Streaming Execution
|
|
311
|
+
|
|
312
|
+
The frontend automatically uses SSE streaming when the server supports it, with transparent fallback to the legacy POST endpoint. Streaming processors emit output chunks as they execute rather than buffering the full response.
|
|
313
|
+
|
|
314
|
+
### Resilience
|
|
315
|
+
|
|
316
|
+
The frontend includes built-in resilience features:
|
|
317
|
+
|
|
318
|
+
- **WebSocket auto-reconnect** with exponential backoff (up to 5 attempts, max 30s delay)
|
|
319
|
+
- **Periodic health checks** for disconnected servers (30s interval)
|
|
320
|
+
- **HTTP retry** on transient fetch failures (1 retry with 1s delay)
|
|
321
|
+
- **Configurable request timeout** per server (default 30s)
|
|
322
|
+
|
|
323
|
+
### Server Plugins
|
|
324
|
+
|
|
325
|
+
| Plugin | Servers | Description |
|
|
326
|
+
|--------|---------|-------------|
|
|
327
|
+
| **Background Jobs** | .NET, Node.js, Python | Scheduled and recurring job execution with cron/interval support |
|
|
328
|
+
| **Admin Dashboard** | .NET, Node.js | React-based web UI for server management — commands, jobs, plugins, logs, filesystem, events, and an embedded terminal |
|
|
329
|
+
| **AWS Cloud** | .NET, Python | S3, EC2, Lambda, DynamoDB, IAM, ECS, SQS, SNS, CloudWatch with multi-profile credential management |
|
|
330
|
+
| **Data Explorer** | .NET, Node.js, Python | SQL, MongoDB, Redis, Elasticsearch, and custom data source providers |
|
|
331
|
+
|
|
332
|
+
### Docker
|
|
333
|
+
|
|
334
|
+
Run all three servers with Docker Compose from the [workspace root](https://github.com/qodalis-solutions/cli-workspace):
|
|
335
|
+
|
|
336
|
+
```bash
|
|
337
|
+
docker compose up --build
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Creating a CLI Plugin
|
|
341
|
+
|
|
342
|
+
### Quick Start
|
|
343
|
+
|
|
344
|
+
Scaffold a complete plugin project with a single command:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
npx @qodalis/create-cli-plugin
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The interactive prompts will ask for:
|
|
351
|
+
|
|
352
|
+
| Prompt | Description | Example |
|
|
353
|
+
|--------|-------------|---------|
|
|
354
|
+
| **Plugin name** | Lowercase, no spaces, no `cli-` prefix (added automatically) | `weather` |
|
|
355
|
+
| **Description** | Short description of the plugin | `Weather forecasts` |
|
|
356
|
+
| **Processor class name** | PascalCase name for the command processor class | `Weather` |
|
|
357
|
+
|
|
358
|
+
You can also skip the prompts by passing arguments directly:
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
npx @qodalis/create-cli-plugin --name weather --description "Weather forecasts" --processor-name Weather
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Or install globally:
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
npm install -g @qodalis/create-cli-plugin
|
|
368
|
+
create-cli-plugin
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Standalone vs Monorepo Mode
|
|
372
|
+
|
|
373
|
+
The tool auto-detects whether you're inside the `web-cli` monorepo:
|
|
374
|
+
|
|
375
|
+
| Mode | Detection | Output directory | Package manager |
|
|
376
|
+
|------|-----------|-----------------|-----------------|
|
|
377
|
+
| **Standalone** | Any directory outside web-cli | `./qodalis-cli-<name>/` | npm or pnpm (auto-detected) |
|
|
378
|
+
| **Monorepo** | Inside web-cli workspace | `packages/plugins/<name>/` | pnpm (workspace) |
|
|
379
|
+
|
|
380
|
+
In monorepo mode, the tool also:
|
|
381
|
+
- Creates `project.json` (Nx build + test targets)
|
|
382
|
+
- Creates `tsconfig.spec.json` (Karma/Jasmine test config)
|
|
383
|
+
- Updates `tsconfig.base.json` with the path alias `@qodalis/cli-<name>` -> `dist/<name>`
|
|
384
|
+
|
|
385
|
+
### Generated Project Structure
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
qodalis-cli-weather/ # or packages/plugins/weather/ in monorepo
|
|
389
|
+
package.json # npm package with CJS/ESM/UMD exports
|
|
390
|
+
tsup.config.ts # Build config (library + IIFE bundles)
|
|
391
|
+
tsconfig.json # TypeScript config
|
|
392
|
+
README.md # Auto-generated README
|
|
393
|
+
src/
|
|
394
|
+
public-api.ts # Public exports + ICliModule declaration
|
|
395
|
+
cli-entrypoint.ts # IIFE entrypoint for browser runtime loading
|
|
396
|
+
lib/
|
|
397
|
+
version.ts # LIBRARY_VERSION + API_VERSION constants
|
|
398
|
+
index.ts # Barrel re-exports
|
|
399
|
+
processors/
|
|
400
|
+
cli-weather-command-processor.ts # Command processor (your main logic goes here)
|
|
401
|
+
tests/
|
|
402
|
+
index.spec.ts # Jasmine test scaffold
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Step-by-Step Workflow
|
|
406
|
+
|
|
407
|
+
#### 1. Scaffold the plugin
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
npx @qodalis/create-cli-plugin --name weather
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
#### 2. Implement your command processor
|
|
414
|
+
|
|
415
|
+
Edit `src/lib/processors/cli-weather-command-processor.ts`:
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
import {
|
|
419
|
+
CliProcessCommand,
|
|
420
|
+
DefaultLibraryAuthor,
|
|
421
|
+
ICliCommandProcessor,
|
|
422
|
+
ICliExecutionContext,
|
|
423
|
+
} from '@qodalis/cli-core';
|
|
424
|
+
import { LIBRARY_VERSION } from '../version';
|
|
425
|
+
|
|
426
|
+
export class CliWeatherCommandProcessor implements ICliCommandProcessor {
|
|
427
|
+
command = 'weather';
|
|
428
|
+
description = 'Weather forecasts';
|
|
429
|
+
author = DefaultLibraryAuthor;
|
|
430
|
+
version = LIBRARY_VERSION;
|
|
431
|
+
|
|
432
|
+
// Sub-commands
|
|
433
|
+
processors?: ICliCommandProcessor[] = [
|
|
434
|
+
{
|
|
435
|
+
command: 'forecast',
|
|
436
|
+
description: 'Get weather forecast for a city',
|
|
437
|
+
parameters: [
|
|
438
|
+
{
|
|
439
|
+
name: 'city',
|
|
440
|
+
aliases: ['c'],
|
|
441
|
+
description: 'City name',
|
|
442
|
+
required: true,
|
|
443
|
+
type: 'string',
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
name: 'days',
|
|
447
|
+
aliases: ['d'],
|
|
448
|
+
description: 'Number of days',
|
|
449
|
+
required: false,
|
|
450
|
+
type: 'number',
|
|
451
|
+
defaultValue: '3',
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
processCommand: async (command, context) => {
|
|
455
|
+
const city = command.args['city'];
|
|
456
|
+
const days = parseInt(command.args['days'] ?? '3');
|
|
457
|
+
context.writer.writeln(`Forecast for ${city} (${days} days):`);
|
|
458
|
+
context.writer.writeSuccess('Sunny, 25°C');
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
command: 'current',
|
|
463
|
+
description: 'Get current weather',
|
|
464
|
+
acceptsRawInput: true, // command.value = text after 'current'
|
|
465
|
+
valueRequired: true, // error if no value provided
|
|
466
|
+
processCommand: async (command, context) => {
|
|
467
|
+
context.writer.writeln(`Current weather in ${command.value}: Sunny, 25°C`);
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
];
|
|
471
|
+
|
|
472
|
+
// Default handler (runs when user types just 'weather')
|
|
473
|
+
async processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void> {
|
|
474
|
+
context.executor.showHelp(command, context);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
#### 3. Build the plugin
|
|
480
|
+
|
|
481
|
+
**Standalone:**
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
cd qodalis-cli-weather
|
|
485
|
+
npm run build # or: npx tsup
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**Monorepo:**
|
|
489
|
+
|
|
490
|
+
```bash
|
|
491
|
+
pnpm nx build weather
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Build output goes to `dist/weather/` with three bundles:
|
|
495
|
+
- `public-api.js` (CJS) + `public-api.mjs` (ESM) + `public-api.d.ts` (types)
|
|
496
|
+
- `umd/index.js` (IIFE — self-contained browser bundle for runtime `pkg add`)
|
|
497
|
+
|
|
498
|
+
#### 4. Test the plugin
|
|
499
|
+
|
|
500
|
+
**Standalone:** Add your preferred test runner.
|
|
501
|
+
|
|
502
|
+
**Monorepo:**
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
pnpm nx test weather
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### 5. Publish to npm
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
cd dist/weather # or: cd qodalis-cli-weather/dist
|
|
512
|
+
npm publish --access public
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
Users can then install your plugin at runtime in any Qodalis CLI terminal:
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
pkg add @qodalis/cli-weather
|
|
519
|
+
weather forecast --city "New York"
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### The ICliModule Export
|
|
523
|
+
|
|
524
|
+
Every plugin exports an `ICliModule` object in `public-api.ts`. This is how frameworks register your plugin:
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
import { ICliModule } from '@qodalis/cli-core';
|
|
528
|
+
import { CliWeatherCommandProcessor } from './lib/processors/cli-weather-command-processor';
|
|
529
|
+
import { API_VERSION } from './lib/version';
|
|
530
|
+
|
|
531
|
+
export const weatherModule: ICliModule = {
|
|
532
|
+
apiVersion: API_VERSION, // must be >= 2
|
|
533
|
+
name: '@qodalis/cli-weather',
|
|
534
|
+
processors: [new CliWeatherCommandProcessor()],
|
|
535
|
+
};
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
`ICliModule` also supports optional lifecycle hooks and configuration:
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
export const weatherModule: ICliModule = {
|
|
542
|
+
apiVersion: 2,
|
|
543
|
+
name: '@qodalis/cli-weather',
|
|
544
|
+
processors: [new CliWeatherCommandProcessor()],
|
|
545
|
+
dependencies: ['@qodalis/cli-curl'], // boot other modules first
|
|
546
|
+
priority: 0, // boot order (lower = first)
|
|
547
|
+
configure(config) { /* ... */ return this; },
|
|
548
|
+
onInit(context) { /* before processors initialize */ },
|
|
549
|
+
onAfterBoot(context) { /* after all modules boot */ },
|
|
550
|
+
onDestroy(context) { /* teardown */ },
|
|
551
|
+
};
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### The IIFE Entrypoint
|
|
555
|
+
|
|
556
|
+
`src/cli-entrypoint.ts` enables runtime loading via `pkg add`. It calls `bootCliModule()` which registers the module with the global `window.__cliModuleRegistry`:
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
import { bootCliModule, ICliModule } from '@qodalis/cli-core';
|
|
560
|
+
import { CliWeatherCommandProcessor } from './lib/processors/cli-weather-command-processor';
|
|
561
|
+
import { API_VERSION } from './lib/version';
|
|
562
|
+
|
|
563
|
+
const module: ICliModule = {
|
|
564
|
+
apiVersion: API_VERSION,
|
|
565
|
+
name: '@qodalis/cli-weather',
|
|
566
|
+
processors: [new CliWeatherCommandProcessor()],
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
bootCliModule(module);
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### Execution Context API
|
|
573
|
+
|
|
574
|
+
The `ICliExecutionContext` passed to `processCommand` provides:
|
|
575
|
+
|
|
576
|
+
| Property | Description |
|
|
577
|
+
|----------|-------------|
|
|
578
|
+
| `context.writer` | Terminal output — `writeln()`, `writeInfo()`, `writeSuccess()`, `writeError()`, `wrapInColor()` |
|
|
579
|
+
| `context.reader` | User input — `readLine()`, `readPassword()`, `readConfirm()`, `readSelect()`, `readMultiSelect()`, `readNumber()` |
|
|
580
|
+
| `context.executor` | Command execution — `showHelp(command, context)` |
|
|
581
|
+
| `context.clipboard` | Clipboard — `write()`, `read()` |
|
|
582
|
+
| `context.state` | Persistent key-value store |
|
|
583
|
+
| `context.progressBar` | Progress bar widget |
|
|
584
|
+
| `context.spinner` | Spinner widget |
|
|
585
|
+
| `context.terminal` | Raw xterm.js `Terminal` instance |
|
|
586
|
+
| `context.onAbort` | `Subject<void>` for Ctrl+C cancellation |
|
|
587
|
+
| `context.enterFullScreenMode()` | Switch to full-screen TUI mode |
|
|
588
|
+
| `context.createInterval()` / `context.createTimeout()` | Managed timers (auto-cleaned on abort) |
|
|
589
|
+
|
|
590
|
+
### Registering Plugins in Your App
|
|
591
|
+
|
|
592
|
+
#### Angular (via providers)
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
import { CliModule, resolveCliModuleProvider } from '@qodalis/angular-cli';
|
|
596
|
+
import { weatherModule } from '@qodalis/cli-weather';
|
|
597
|
+
|
|
598
|
+
@NgModule({
|
|
599
|
+
imports: [CliModule],
|
|
600
|
+
providers: [resolveCliModuleProvider(weatherModule)],
|
|
601
|
+
})
|
|
602
|
+
export class AppModule {}
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
#### Angular (via template input)
|
|
606
|
+
|
|
607
|
+
```typescript
|
|
608
|
+
import { weatherModule } from '@qodalis/cli-weather';
|
|
609
|
+
|
|
610
|
+
export class AppComponent {
|
|
611
|
+
modules = [weatherModule];
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
```html
|
|
616
|
+
<cli [modules]="modules" />
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
#### React
|
|
620
|
+
|
|
621
|
+
```tsx
|
|
622
|
+
import { CliConfigProvider, Cli } from '@qodalis/react-cli';
|
|
623
|
+
import { weatherModule } from '@qodalis/cli-weather';
|
|
624
|
+
|
|
625
|
+
function App() {
|
|
626
|
+
return (
|
|
627
|
+
<CliConfigProvider modules={[weatherModule]}>
|
|
628
|
+
<Cli />
|
|
629
|
+
</CliConfigProvider>
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
#### Vue
|
|
635
|
+
|
|
636
|
+
```vue
|
|
637
|
+
<script setup lang="ts">
|
|
638
|
+
import { CliConfigProvider, Cli } from '@qodalis/vue-cli';
|
|
639
|
+
import { weatherModule } from '@qodalis/cli-weather';
|
|
640
|
+
</script>
|
|
641
|
+
|
|
642
|
+
<template>
|
|
643
|
+
<CliConfigProvider :modules="[weatherModule]">
|
|
644
|
+
<Cli />
|
|
645
|
+
</CliConfigProvider>
|
|
646
|
+
</template>
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
## Data Explorer
|
|
650
|
+
|
|
651
|
+
The `@qodalis/cli-data-explorer` plugin adds an interactive, full-screen REPL for querying data sources (SQL, MongoDB, Redis, Elasticsearch, and custom providers) directly from the terminal.
|
|
652
|
+
|
|
653
|
+
### Setup
|
|
654
|
+
|
|
655
|
+
Install and register the plugin, then configure backend servers:
|
|
656
|
+
|
|
657
|
+
```typescript
|
|
658
|
+
import { dataExplorerModule } from '@qodalis/cli-data-explorer';
|
|
659
|
+
|
|
660
|
+
// Add to your modules array
|
|
661
|
+
const modules = [dataExplorerModule, /* ... other modules */];
|
|
662
|
+
|
|
663
|
+
// Configure at least one server with data explorer providers
|
|
664
|
+
const options: CliOptions = {
|
|
665
|
+
servers: [
|
|
666
|
+
{ name: 'node', url: 'http://localhost:8047' },
|
|
667
|
+
{ name: 'dotnet', url: 'http://localhost:8046' },
|
|
668
|
+
{ name: 'python', url: 'http://localhost:8048' },
|
|
669
|
+
],
|
|
670
|
+
};
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
Or install at runtime without a rebuild:
|
|
674
|
+
|
|
675
|
+
```bash
|
|
676
|
+
pkg add data-explorer
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### Usage
|
|
680
|
+
|
|
681
|
+
```bash
|
|
682
|
+
data-explorer
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
Select a server and data source, then enter the full-screen REPL:
|
|
686
|
+
|
|
687
|
+
```
|
|
688
|
+
data-explorer> SELECT * FROM users WHERE active = true;
|
|
689
|
+
|
|
690
|
+
3 rows (12ms)
|
|
691
|
+
┌────┬───────┬──────────────┐
|
|
692
|
+
│ id │ name │ email │
|
|
693
|
+
├────┼───────┼──────────────┤
|
|
694
|
+
│ 1 │ Alice │ alice@ex.com │
|
|
695
|
+
│ 2 │ Bob │ bob@ex.com │
|
|
696
|
+
│ 3 │ Carol │ carol@ex.com │
|
|
697
|
+
└────┴───────┴──────────────┘
|
|
698
|
+
|
|
699
|
+
data-explorer> \format json
|
|
700
|
+
Output format set to: json
|
|
701
|
+
|
|
702
|
+
data-explorer> db.users.find({"age": {"$gt": 25}})
|
|
703
|
+
[
|
|
704
|
+
{ "_id": "abc", "name": "Alice", "age": 30 },
|
|
705
|
+
{ "_id": "def", "name": "Bob", "age": 28 }
|
|
706
|
+
]
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
### REPL Commands
|
|
710
|
+
|
|
711
|
+
| Command | Description |
|
|
712
|
+
|---------|-------------|
|
|
713
|
+
| `\format <table\|json\|csv\|raw>` | Switch output format |
|
|
714
|
+
| `\schema` | Show database schema (tables, columns, types) |
|
|
715
|
+
| `\templates` | List available query templates |
|
|
716
|
+
| `\use <name>` | Load a template query |
|
|
717
|
+
| `\history` | Show query history |
|
|
718
|
+
| `\clear` | Clear screen |
|
|
719
|
+
| `\help` | Show all commands |
|
|
720
|
+
| `\quit` / `\q` | Exit |
|
|
721
|
+
|
|
722
|
+
Use **Up/Down arrows** for history navigation, **Escape** or **Ctrl+C** to exit.
|
|
723
|
+
|
|
724
|
+
## Extending with Inline Commands
|
|
725
|
+
|
|
726
|
+
For quick one-off commands without creating a full plugin, implement `ICliCommandProcessor` directly in your app:
|
|
176
727
|
|
|
177
728
|
```typescript
|
|
178
729
|
import {
|
|
@@ -184,7 +735,7 @@ import {
|
|
|
184
735
|
export class GreetCommandProcessor implements ICliCommandProcessor {
|
|
185
736
|
command = 'greet';
|
|
186
737
|
description = 'Greet someone by name';
|
|
187
|
-
|
|
738
|
+
acceptsRawInput = true;
|
|
188
739
|
valueRequired = true;
|
|
189
740
|
|
|
190
741
|
async processCommand(
|
|
@@ -196,16 +747,14 @@ export class GreetCommandProcessor implements ICliCommandProcessor {
|
|
|
196
747
|
}
|
|
197
748
|
```
|
|
198
749
|
|
|
199
|
-
Register it
|
|
750
|
+
Register it with your framework (Angular: `resolveCommandProcessorProvider(GreetCommandProcessor)`, React/Vue: pass via `processors` prop), or wrap it in an inline `ICliModule`:
|
|
200
751
|
|
|
201
752
|
```typescript
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
})
|
|
208
|
-
export class AppModule {}
|
|
753
|
+
const myModule: ICliModule = {
|
|
754
|
+
apiVersion: 2,
|
|
755
|
+
name: 'my-app-commands',
|
|
756
|
+
processors: [new GreetCommandProcessor()],
|
|
757
|
+
};
|
|
209
758
|
```
|
|
210
759
|
|
|
211
760
|
```bash
|
|
@@ -213,16 +762,39 @@ export class AppModule {}
|
|
|
213
762
|
Hello, World!
|
|
214
763
|
```
|
|
215
764
|
|
|
765
|
+
## Using the Engine Directly
|
|
766
|
+
|
|
767
|
+
For advanced use cases or non-framework environments, use `CliEngine` directly:
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
import { CliEngine } from '@qodalis/cli';
|
|
771
|
+
|
|
772
|
+
const engine = new CliEngine(document.getElementById('terminal')!, {
|
|
773
|
+
welcomeMessage: { message: 'Welcome!', show: 'always' },
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
engine.registerProcessors([new GreetCommandProcessor()]);
|
|
777
|
+
await engine.start();
|
|
778
|
+
```
|
|
779
|
+
|
|
216
780
|
## Features
|
|
217
781
|
|
|
218
|
-
- **
|
|
782
|
+
- **Multi-framework** — Angular, React, Vue, or vanilla JS
|
|
783
|
+
- **38 official plugins** — 24 utility, 6 games, 10 language packs
|
|
784
|
+
- **Command chaining** with `&&`, `||`, `|`, and `>>` operators
|
|
219
785
|
- **Command history** with arrow key navigation
|
|
220
786
|
- **Tab-like completions** and keyboard shortcuts (`Ctrl+C`, `Ctrl+L`, `Escape`)
|
|
221
|
-
- **
|
|
787
|
+
- **29 built-in themes** with custom color support
|
|
788
|
+
- **Tabs & split panes** — multiple terminals in tabs with horizontal splitting
|
|
222
789
|
- **User sessions** with multi-user support
|
|
223
790
|
- **State persistence** across sessions
|
|
791
|
+
- **Interactive prompts** with live preview (select menus with real-time feedback)
|
|
792
|
+
- **Full-screen mode API** for rich TUI commands (games, editors, pagers)
|
|
224
793
|
- **Progress bars, spinners, and text animations**
|
|
225
794
|
- **Runtime package installation** from npm
|
|
795
|
+
- **Server integration** with SSE streaming, auto-reconnect, and health checks
|
|
796
|
+
- **Admin dashboard** for server management (React SPA)
|
|
797
|
+
- **Data explorer** for SQL, MongoDB, Redis, and Elasticsearch
|
|
226
798
|
|
|
227
799
|
## Contributing
|
|
228
800
|
|