@qodalis/cli 2.0.0-beta.14 → 2.0.0-beta.16

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 CHANGED
@@ -288,6 +288,7 @@ All three implement the same API surface:
288
288
  | `/ws/v1/cli/events` | WS | Server-push event streaming |
289
289
  | `/ws/v1/cli/shell` | WS | Interactive PTY shell session |
290
290
  | `/api/cli/fs/*` | Various | Filesystem operations (ls, cat, upload, download, mkdir, rm) |
291
+ | `/api/qcli/mcp` | POST | MCP endpoint for AI clients (opt-in) |
291
292
 
292
293
  ### Connecting to a Server
293
294
 
@@ -320,6 +321,19 @@ The frontend includes built-in resilience features:
320
321
  - **HTTP retry** on transient fetch failures (1 retry with 1s delay)
321
322
  - **Configurable request timeout** per server (default 30s)
322
323
 
324
+ ### MCP
325
+
326
+ Each server can expose the whole system to AI clients such as Claude Code over the [Model Context Protocol](https://modelcontextprotocol.io) at `POST /api/qcli/mcp` (opt-in): CLI commands, the filesystem API, the data explorer, jobs and plugin-contributed tools, each with the caller's permissions. It works with or without the users plugin, whose `token create` command issues the API tokens MCP clients sign in with:
327
+
328
+ ```bash
329
+ # direct HTTP
330
+ claude mcp add --transport http qcli http://localhost:8047/api/qcli/mcp --header "Authorization: Bearer <token>"
331
+ # or the local stdio proxy @qodalis/mcp-cli (token or user/password, read-only mode, tool filters)
332
+ claude mcp add qcli -e QCLI_URL=http://localhost:8047 -e QCLI_TOKEN=<token> -- npx -y @qodalis/mcp-cli
333
+ ```
334
+
335
+ See [MCP endpoint](https://cli.qodalis.com/docs/server-integration#mcp-endpoint) for enabling it, the tools and permissions, and client setup.
336
+
323
337
  ### Server Plugins
324
338
 
325
339
  | Plugin | Servers | Description |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qodalis/cli",
3
- "version": "2.0.0-beta.14",
3
+ "version": "2.0.0-beta.16",
4
4
  "description": "Framework-agnostic CLI engine for @qodalis terminal applications.",
5
5
  "author": "Nicolae Lupei, Qodalis Solutions",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "./assets/*": "./assets/*"
31
31
  },
32
32
  "dependencies": {
33
- "@qodalis/cli-core": "2.0.0-beta.14",
33
+ "@qodalis/cli-core": "2.0.0-beta.16",
34
34
  "@xterm/xterm": "^5.5.0",
35
35
  "@xterm/addon-fit": "^0.10.0",
36
36
  "@xterm/addon-web-links": "^0.11.0",
package/public-api.d.mts CHANGED
@@ -153,7 +153,7 @@ declare const CliKeyValueStore_TOKEN = "cli-key-value-store";
153
153
  */
154
154
  declare const SyntaxHighlighterRegistry_TOKEN = "syntax-highlighter-registry";
155
155
 
156
- declare const LIBRARY_VERSION = "2.0.0-beta.14";
156
+ declare const LIBRARY_VERSION = "2.0.0-beta.16";
157
157
  declare const API_VERSION = 2;
158
158
 
159
159
  declare class CliAliasCommandProcessor implements ICliCommandProcessor {
package/public-api.d.ts CHANGED
@@ -153,7 +153,7 @@ declare const CliKeyValueStore_TOKEN = "cli-key-value-store";
153
153
  */
154
154
  declare const SyntaxHighlighterRegistry_TOKEN = "syntax-highlighter-registry";
155
155
 
156
- declare const LIBRARY_VERSION = "2.0.0-beta.14";
156
+ declare const LIBRARY_VERSION = "2.0.0-beta.16";
157
157
  declare const API_VERSION = 2;
158
158
 
159
159
  declare class CliAliasCommandProcessor implements ICliCommandProcessor {
package/public-api.js CHANGED
@@ -413,7 +413,7 @@ var CliKeyValueStore_TOKEN = "cli-key-value-store";
413
413
  var SyntaxHighlighterRegistry_TOKEN = "syntax-highlighter-registry";
414
414
 
415
415
  // src/lib/version.ts
416
- var LIBRARY_VERSION = "2.0.0-beta.14";
416
+ var LIBRARY_VERSION = "2.0.0-beta.16";
417
417
  var API_VERSION = 2;
418
418
  var ANONYMOUS = "\0anonymous";
419
419
  function aliasOwner(context2) {
@@ -12344,8 +12344,6 @@ var CliClipboard = class {
12344
12344
  }
12345
12345
  }
12346
12346
  };
12347
-
12348
- // src/lib/input/modes/input-mode-base.ts
12349
12347
  var InputModeBase = class {
12350
12348
  constructor(host, resolve) {
12351
12349
  this.host = host;
@@ -12414,6 +12412,17 @@ var InputModeBase = class {
12414
12412
  }
12415
12413
  this.host.terminal.write(buf);
12416
12414
  }
12415
+ /**
12416
+ * Cut a line to the terminal width. Lines redrawn in place must stay on one row:
12417
+ * a wrapped line takes two rows and breaks the cursor-up arithmetic of the redraw.
12418
+ */
12419
+ fitLine(text) {
12420
+ return cliCore.truncateToWidth(text, Math.max(1, this.host.getTerminalCols() - 1));
12421
+ }
12422
+ /** Start a new row and write `text` cut to the terminal width. */
12423
+ writeRow(text) {
12424
+ this.host.terminal.write("\r\n" + this.fitLine(text));
12425
+ }
12417
12426
  /**
12418
12427
  * Render a dimmed help bar below the current line.
12419
12428
  */
@@ -12421,7 +12430,7 @@ var InputModeBase = class {
12421
12430
  this.extraLines++;
12422
12431
  this.host.terminal.write(
12423
12432
  `\r
12424
- \x1B[2m${text}\x1B[0m\x1B[${this.extraLines}A`
12433
+ ${this.fitLine(` \x1B[2m${text}\x1B[0m`)}\x1B[${this.extraLines}A`
12425
12434
  );
12426
12435
  }
12427
12436
  /**
@@ -12431,7 +12440,7 @@ var InputModeBase = class {
12431
12440
  this.extraLines++;
12432
12441
  this.host.terminal.write(
12433
12442
  `\r
12434
- \x1B[31m\u2718 ${message}\x1B[0m\x1B[${this.extraLines}A`
12443
+ ${this.fitLine(` \x1B[31m\u2718 ${message}\x1B[0m`)}\x1B[${this.extraLines}A`
12435
12444
  );
12436
12445
  }
12437
12446
  /**
@@ -12933,15 +12942,15 @@ var SelectInputMode = class extends InputModeBase {
12933
12942
  if (this.selectOptions?.searchable) {
12934
12943
  if (this.filter.length > 0) {
12935
12944
  this.host.terminal.write(
12936
- `\x1B[36m?\x1B[0m ${this.promptText}: ${this.filter}`
12945
+ this.fitLine(`\x1B[36m?\x1B[0m ${this.promptText}: ${this.filter}`)
12937
12946
  );
12938
12947
  } else {
12939
12948
  this.host.terminal.write(
12940
- `\x1B[36m?\x1B[0m ${this.promptText}: \x1B[2mType to filter...\x1B[0m`
12949
+ this.fitLine(`\x1B[36m?\x1B[0m ${this.promptText}: \x1B[2mType to filter...\x1B[0m`)
12941
12950
  );
12942
12951
  }
12943
12952
  } else {
12944
- this.host.terminal.write(`\x1B[36m?\x1B[0m ${this.promptText}:`);
12953
+ this.host.terminal.write(this.fitLine(`\x1B[36m?\x1B[0m ${this.promptText}:`));
12945
12954
  }
12946
12955
  }
12947
12956
  /**
@@ -12956,17 +12965,15 @@ var SelectInputMode = class extends InputModeBase {
12956
12965
  this.scrollOffset + this.maxVisible
12957
12966
  );
12958
12967
  if (visibleStart > 0) {
12959
- this.host.terminal.write(`\r
12960
- \x1B[2m \u2191 ${visibleStart} more above\x1B[0m`);
12968
+ this.writeRow(`\x1B[2m \u2191 ${visibleStart} more above\x1B[0m`);
12961
12969
  this.renderedLines++;
12962
12970
  }
12963
12971
  let selectableIdx = 0;
12964
12972
  for (const item of items) {
12965
12973
  if (item.type === "group-header") {
12966
12974
  if (this.isGroupVisible(item.groupName, items, visibleStart, visibleEnd)) {
12967
- this.host.terminal.write(
12968
- `\r
12969
- \x1B[35m\u2500\u2500 ${item.groupName} \u2500\u2500\x1B[0m`
12975
+ this.writeRow(
12976
+ `\x1B[35m\u2500\u2500 ${item.groupName} \u2500\u2500\x1B[0m`
12970
12977
  );
12971
12978
  this.renderedLines++;
12972
12979
  }
@@ -12989,8 +12996,7 @@ var SelectInputMode = class extends InputModeBase {
12989
12996
  }
12990
12997
  const remaining = selectables.length - visibleEnd;
12991
12998
  if (remaining > 0) {
12992
- this.host.terminal.write(`\r
12993
- \x1B[2m \u2193 ${remaining} more below\x1B[0m`);
12999
+ this.writeRow(`\x1B[2m \u2193 ${remaining} more below\x1B[0m`);
12994
13000
  this.renderedLines++;
12995
13001
  }
12996
13002
  }
@@ -13032,19 +13038,16 @@ var SelectInputMode = class extends InputModeBase {
13032
13038
  const label = this.highlightMatch(opt.label);
13033
13039
  const desc = opt.description ? ` \x1B[2;3m\u2014 ${opt.description}\x1B[0m` : "";
13034
13040
  if (opt.disabled) {
13035
- this.host.terminal.write(
13036
- `\r
13037
- \x1B[2m${opt.label}${desc} (disabled)\x1B[0m`
13041
+ this.writeRow(
13042
+ ` \x1B[2m${opt.label}${desc} (disabled)\x1B[0m`
13038
13043
  );
13039
13044
  } else if (isSelected) {
13040
- this.host.terminal.write(
13041
- `\r
13042
- \x1B[48;5;24m\x1B[38;5;117m\u276F ${label}${desc}\x1B[0m`
13045
+ this.writeRow(
13046
+ ` \x1B[48;5;24m\x1B[38;5;117m\u276F ${label}${desc}\x1B[0m`
13043
13047
  );
13044
13048
  } else {
13045
- this.host.terminal.write(
13046
- `\r
13047
- ${label}${desc}`
13049
+ this.writeRow(
13050
+ ` ${label}${desc}`
13048
13051
  );
13049
13052
  }
13050
13053
  }
@@ -13078,8 +13081,7 @@ var SelectInputMode = class extends InputModeBase {
13078
13081
  } else {
13079
13082
  help = "\u2191/\u2193 navigate \xB7 enter to select \xB7 esc to cancel";
13080
13083
  }
13081
- this.host.terminal.write(`\r
13082
- \x1B[2m${help}\x1B[0m`);
13084
+ this.writeRow(` \x1B[2m${help}\x1B[0m`);
13083
13085
  this.renderedLines++;
13084
13086
  }
13085
13087
  };
@@ -13557,15 +13559,15 @@ var MultiSelectInputMode = class extends InputModeBase {
13557
13559
  if (this.selectOptions?.searchable) {
13558
13560
  if (this.filter.length > 0) {
13559
13561
  this.host.terminal.write(
13560
- `\x1B[36m?\x1B[0m ${this.promptText}: ${this.filter}`
13562
+ this.fitLine(`\x1B[36m?\x1B[0m ${this.promptText}: ${this.filter}`)
13561
13563
  );
13562
13564
  } else {
13563
13565
  this.host.terminal.write(
13564
- `\x1B[36m?\x1B[0m ${this.promptText}: \x1B[2mType to filter...\x1B[0m`
13566
+ this.fitLine(`\x1B[36m?\x1B[0m ${this.promptText}: \x1B[2mType to filter...\x1B[0m`)
13565
13567
  );
13566
13568
  }
13567
13569
  } else {
13568
- this.host.terminal.write(`\x1B[36m?\x1B[0m ${this.promptText}:`);
13570
+ this.host.terminal.write(this.fitLine(`\x1B[36m?\x1B[0m ${this.promptText}:`));
13569
13571
  }
13570
13572
  }
13571
13573
  /**
@@ -13580,17 +13582,15 @@ var MultiSelectInputMode = class extends InputModeBase {
13580
13582
  this.scrollOffset + this.maxVisible
13581
13583
  );
13582
13584
  if (visibleStart > 0) {
13583
- this.host.terminal.write(`\r
13584
- \x1B[2m \u2191 ${visibleStart} more above\x1B[0m`);
13585
+ this.writeRow(`\x1B[2m \u2191 ${visibleStart} more above\x1B[0m`);
13585
13586
  this.renderedLines++;
13586
13587
  }
13587
13588
  let selectableIdx = 0;
13588
13589
  for (const item of items) {
13589
13590
  if (item.type === "group-header") {
13590
13591
  if (this.isGroupVisible(item.groupName, items, visibleStart, visibleEnd)) {
13591
- this.host.terminal.write(
13592
- `\r
13593
- \x1B[35m\u2500\u2500 ${item.groupName} \u2500\u2500\x1B[0m`
13592
+ this.writeRow(
13593
+ `\x1B[35m\u2500\u2500 ${item.groupName} \u2500\u2500\x1B[0m`
13594
13594
  );
13595
13595
  this.renderedLines++;
13596
13596
  }
@@ -13613,8 +13613,7 @@ var MultiSelectInputMode = class extends InputModeBase {
13613
13613
  }
13614
13614
  const remaining = selectables.length - visibleEnd;
13615
13615
  if (remaining > 0) {
13616
- this.host.terminal.write(`\r
13617
- \x1B[2m \u2193 ${remaining} more below\x1B[0m`);
13616
+ this.writeRow(`\x1B[2m \u2193 ${remaining} more below\x1B[0m`);
13618
13617
  this.renderedLines++;
13619
13618
  }
13620
13619
  }
@@ -13659,19 +13658,16 @@ var MultiSelectInputMode = class extends InputModeBase {
13659
13658
  const checkbox = isChecked ? "\x1B[32m\u25C9\x1B[0m" : "\x1B[2m\u25CB\x1B[0m";
13660
13659
  if (opt.disabled) {
13661
13660
  const disabledCheckbox = isChecked ? "\x1B[2m\u25C9\x1B[0m" : "\x1B[2m\u25CB\x1B[0m";
13662
- this.host.terminal.write(
13663
- `\r
13664
- ${disabledCheckbox} \x1B[2m${opt.label}${desc} (disabled)\x1B[0m`
13661
+ this.writeRow(
13662
+ ` ${disabledCheckbox} \x1B[2m${opt.label}${desc} (disabled)\x1B[0m`
13665
13663
  );
13666
13664
  } else if (isSelected) {
13667
- this.host.terminal.write(
13668
- `\r
13669
- \x1B[48;5;24m\x1B[38;5;117m\u276F ${checkbox} ${label}${desc}\x1B[0m`
13665
+ this.writeRow(
13666
+ ` \x1B[48;5;24m\x1B[38;5;117m\u276F ${checkbox} ${label}${desc}\x1B[0m`
13670
13667
  );
13671
13668
  } else {
13672
- this.host.terminal.write(
13673
- `\r
13674
- ${checkbox} ${label}${desc}`
13669
+ this.writeRow(
13670
+ ` ${checkbox} ${label}${desc}`
13675
13671
  );
13676
13672
  }
13677
13673
  }
@@ -13706,8 +13702,7 @@ var MultiSelectInputMode = class extends InputModeBase {
13706
13702
  } else {
13707
13703
  help = `${checkedCount} selected \xB7 space to toggle \xB7 a to select all \xB7 enter to confirm`;
13708
13704
  }
13709
- this.host.terminal.write(`\r
13710
- \x1B[2m${help}\x1B[0m`);
13705
+ this.writeRow(` \x1B[2m${help}\x1B[0m`);
13711
13706
  this.renderedLines++;
13712
13707
  }
13713
13708
  };