@qodalis/cli 2.0.0-beta.19 → 2.0.0-beta.20
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 +3 -3
- package/package.json +2 -2
- package/public-api.d.mts +26 -2
- package/public-api.d.ts +26 -2
- package/public-api.js +234 -67
- package/public-api.js.map +1 -1
- package/public-api.mjs +234 -67
- package/public-api.mjs.map +1 -1
package/README.md
CHANGED
|
@@ -136,7 +136,7 @@ const options = {
|
|
|
136
136
|
| `help` | `man` | Show all commands or help for a specific command |
|
|
137
137
|
| `version` | `ver` | Display CLI version and documentation link |
|
|
138
138
|
| `hotkeys` | `shortcuts`, `keys` | Show keyboard shortcuts |
|
|
139
|
-
| `history` | `hist` | Browse and clear command history |
|
|
139
|
+
| `history` | `hist` | Browse and clear your command history (per user with the users plugin) |
|
|
140
140
|
| `theme` | `themes` | Apply, customize, and save terminal themes (interactive selection with live preview) |
|
|
141
141
|
| `feedback` | `support` | Report bugs or request features on GitHub |
|
|
142
142
|
| `pkg` | `packages` | Install, update, remove, and browse packages |
|
|
@@ -796,8 +796,8 @@ await engine.start();
|
|
|
796
796
|
- **Multi-framework** — Angular, React, Vue, or vanilla JS
|
|
797
797
|
- **38 official plugins** — 24 utility, 6 games, 10 language packs
|
|
798
798
|
- **Command chaining** with `&&`, `||`, `|`, and `>>` operators
|
|
799
|
-
- **Command history** with arrow key navigation
|
|
800
|
-
- **Tab-like completions** and keyboard shortcuts (`Ctrl+C`, `Ctrl+L`, `Escape`)
|
|
799
|
+
- **Command history** with arrow key navigation, per user when the users plugin is used (like `~/.bash_history`)
|
|
800
|
+
- **Tab-like completions** and readline keyboard shortcuts (`Ctrl+C`, `Ctrl+L`, `Escape`, `Ctrl+A/E`, `Ctrl+U/K/W/Y`, Home/End; `hotkeys` lists them)
|
|
801
801
|
- **29 built-in themes** with custom color support
|
|
802
802
|
- **Tabs & split panes** — multiple terminals in tabs with horizontal splitting
|
|
803
803
|
- **User sessions** with multi-user support
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qodalis/cli",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.20",
|
|
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.
|
|
33
|
+
"@qodalis/cli-core": "2.0.0-beta.20",
|
|
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
|
@@ -165,7 +165,7 @@ declare const CliKeyValueStore_TOKEN: any;
|
|
|
165
165
|
*/
|
|
166
166
|
declare const SyntaxHighlighterRegistry_TOKEN: any;
|
|
167
167
|
|
|
168
|
-
declare const LIBRARY_VERSION = "2.0.0-beta.
|
|
168
|
+
declare const LIBRARY_VERSION = "2.0.0-beta.20";
|
|
169
169
|
declare const API_VERSION = 2;
|
|
170
170
|
|
|
171
171
|
declare class CliAliasCommandProcessor implements ICliCommandProcessor {
|
|
@@ -1025,11 +1025,29 @@ declare class CliCommandExecutionContext implements ICliExecutionContext {
|
|
|
1025
1025
|
constructor(context: ICliExecutionContext, processor: ICliCommandProcessor);
|
|
1026
1026
|
}
|
|
1027
1027
|
|
|
1028
|
+
/**
|
|
1029
|
+
* Command history, kept per user like a shell's `~/.bash_history`: each
|
|
1030
|
+
* signed-in user (by id) has their own, and the shared one is used while
|
|
1031
|
+
* nobody is signed in.
|
|
1032
|
+
*/
|
|
1028
1033
|
declare class CliCommandHistory {
|
|
1029
1034
|
private readonly store;
|
|
1030
|
-
private readonly storageKey;
|
|
1031
1035
|
private commandHistory;
|
|
1036
|
+
/** Id of the user whose history is loaded; undefined: nobody signed in */
|
|
1037
|
+
private userId;
|
|
1038
|
+
private loading;
|
|
1039
|
+
/** Counts user switches (a load for an older one is dropped) */
|
|
1040
|
+
private switches;
|
|
1041
|
+
private _generation;
|
|
1032
1042
|
constructor(store: ICliKeyValueStore);
|
|
1043
|
+
/** Changes whenever the history is replaced: switched or loaded (positions into it are stale) */
|
|
1044
|
+
get generation(): number;
|
|
1045
|
+
private get storageKey();
|
|
1046
|
+
/**
|
|
1047
|
+
* Switch to the history of `userId` (undefined: nobody signed in).
|
|
1048
|
+
* Resolves once it is loaded; a no-op for the user already loaded.
|
|
1049
|
+
*/
|
|
1050
|
+
useUser(userId: string | undefined): Promise<void>;
|
|
1033
1051
|
addCommand(command: string): Promise<void>;
|
|
1034
1052
|
getLastIndex(): number;
|
|
1035
1053
|
getHistory(): string[];
|
|
@@ -1173,6 +1191,12 @@ declare class CliLineBuffer {
|
|
|
1173
1191
|
moveEnd(): void;
|
|
1174
1192
|
clear(): void;
|
|
1175
1193
|
setText(str: string): void;
|
|
1194
|
+
/** Remove the text before the cursor (Ctrl+U); returns it */
|
|
1195
|
+
deleteToStart(): string;
|
|
1196
|
+
/** Remove the text from the cursor to the end (Ctrl+K); returns it */
|
|
1197
|
+
deleteToEnd(): string;
|
|
1198
|
+
/** Remove the whitespace-delimited word before the cursor (Ctrl+W); returns it */
|
|
1199
|
+
deleteWordBefore(): string;
|
|
1176
1200
|
}
|
|
1177
1201
|
|
|
1178
1202
|
/**
|
package/public-api.d.ts
CHANGED
|
@@ -165,7 +165,7 @@ declare const CliKeyValueStore_TOKEN: any;
|
|
|
165
165
|
*/
|
|
166
166
|
declare const SyntaxHighlighterRegistry_TOKEN: any;
|
|
167
167
|
|
|
168
|
-
declare const LIBRARY_VERSION = "2.0.0-beta.
|
|
168
|
+
declare const LIBRARY_VERSION = "2.0.0-beta.20";
|
|
169
169
|
declare const API_VERSION = 2;
|
|
170
170
|
|
|
171
171
|
declare class CliAliasCommandProcessor implements ICliCommandProcessor {
|
|
@@ -1025,11 +1025,29 @@ declare class CliCommandExecutionContext implements ICliExecutionContext {
|
|
|
1025
1025
|
constructor(context: ICliExecutionContext, processor: ICliCommandProcessor);
|
|
1026
1026
|
}
|
|
1027
1027
|
|
|
1028
|
+
/**
|
|
1029
|
+
* Command history, kept per user like a shell's `~/.bash_history`: each
|
|
1030
|
+
* signed-in user (by id) has their own, and the shared one is used while
|
|
1031
|
+
* nobody is signed in.
|
|
1032
|
+
*/
|
|
1028
1033
|
declare class CliCommandHistory {
|
|
1029
1034
|
private readonly store;
|
|
1030
|
-
private readonly storageKey;
|
|
1031
1035
|
private commandHistory;
|
|
1036
|
+
/** Id of the user whose history is loaded; undefined: nobody signed in */
|
|
1037
|
+
private userId;
|
|
1038
|
+
private loading;
|
|
1039
|
+
/** Counts user switches (a load for an older one is dropped) */
|
|
1040
|
+
private switches;
|
|
1041
|
+
private _generation;
|
|
1032
1042
|
constructor(store: ICliKeyValueStore);
|
|
1043
|
+
/** Changes whenever the history is replaced: switched or loaded (positions into it are stale) */
|
|
1044
|
+
get generation(): number;
|
|
1045
|
+
private get storageKey();
|
|
1046
|
+
/**
|
|
1047
|
+
* Switch to the history of `userId` (undefined: nobody signed in).
|
|
1048
|
+
* Resolves once it is loaded; a no-op for the user already loaded.
|
|
1049
|
+
*/
|
|
1050
|
+
useUser(userId: string | undefined): Promise<void>;
|
|
1033
1051
|
addCommand(command: string): Promise<void>;
|
|
1034
1052
|
getLastIndex(): number;
|
|
1035
1053
|
getHistory(): string[];
|
|
@@ -1173,6 +1191,12 @@ declare class CliLineBuffer {
|
|
|
1173
1191
|
moveEnd(): void;
|
|
1174
1192
|
clear(): void;
|
|
1175
1193
|
setText(str: string): void;
|
|
1194
|
+
/** Remove the text before the cursor (Ctrl+U); returns it */
|
|
1195
|
+
deleteToStart(): string;
|
|
1196
|
+
/** Remove the text from the cursor to the end (Ctrl+K); returns it */
|
|
1197
|
+
deleteToEnd(): string;
|
|
1198
|
+
/** Remove the whitespace-delimited word before the cursor (Ctrl+W); returns it */
|
|
1199
|
+
deleteWordBefore(): string;
|
|
1176
1200
|
}
|
|
1177
1201
|
|
|
1178
1202
|
/**
|
package/public-api.js
CHANGED
|
@@ -512,7 +512,7 @@ var CliKeyValueStore_TOKEN = cliCore.createCliToken("cli-key-value-store");
|
|
|
512
512
|
var SyntaxHighlighterRegistry_TOKEN = cliCore.createCliToken("syntax-highlighter-registry");
|
|
513
513
|
|
|
514
514
|
// src/lib/version.ts
|
|
515
|
-
var LIBRARY_VERSION = "2.0.0-beta.
|
|
515
|
+
var LIBRARY_VERSION = "2.0.0-beta.20";
|
|
516
516
|
var API_VERSION = 2;
|
|
517
517
|
var ANONYMOUS = "\0anonymous";
|
|
518
518
|
function aliasOwner(context2) {
|
|
@@ -5686,13 +5686,45 @@ var hotkeysInfo = [
|
|
|
5686
5686
|
key: "Ctrl + L",
|
|
5687
5687
|
description: "Clear the terminal screen"
|
|
5688
5688
|
},
|
|
5689
|
+
{
|
|
5690
|
+
key: "Escape",
|
|
5691
|
+
description: "Cancel and start a new line"
|
|
5692
|
+
},
|
|
5689
5693
|
{
|
|
5690
5694
|
key: "\u2191 / \u2193",
|
|
5691
|
-
description: "Navigate command history"
|
|
5695
|
+
description: "Navigate command history (each user has their own)"
|
|
5692
5696
|
},
|
|
5693
5697
|
{
|
|
5694
5698
|
key: "Tab",
|
|
5695
5699
|
description: "Autocomplete command"
|
|
5700
|
+
},
|
|
5701
|
+
{
|
|
5702
|
+
key: "Ctrl + A / Home",
|
|
5703
|
+
description: "Move to the start of the line"
|
|
5704
|
+
},
|
|
5705
|
+
{
|
|
5706
|
+
key: "Ctrl + E / End",
|
|
5707
|
+
description: "Move to the end of the line"
|
|
5708
|
+
},
|
|
5709
|
+
{
|
|
5710
|
+
key: "Ctrl + U",
|
|
5711
|
+
description: "Cut from the start of the line to the cursor"
|
|
5712
|
+
},
|
|
5713
|
+
{
|
|
5714
|
+
key: "Ctrl + K",
|
|
5715
|
+
description: "Cut from the cursor to the end of the line"
|
|
5716
|
+
},
|
|
5717
|
+
{
|
|
5718
|
+
key: "Ctrl + W",
|
|
5719
|
+
description: "Cut the previous word (also Alt + Backspace)"
|
|
5720
|
+
},
|
|
5721
|
+
{
|
|
5722
|
+
key: "Ctrl + Y",
|
|
5723
|
+
description: "Paste the last cut text"
|
|
5724
|
+
},
|
|
5725
|
+
{
|
|
5726
|
+
key: "Ctrl + D / Del",
|
|
5727
|
+
description: "Delete the character under the cursor"
|
|
5696
5728
|
}
|
|
5697
5729
|
];
|
|
5698
5730
|
|
|
@@ -6136,7 +6168,7 @@ var CliHotKeysCommandProcessor = class {
|
|
|
6136
6168
|
const { writer } = context2;
|
|
6137
6169
|
hotkeysInfo.forEach((hotkey) => {
|
|
6138
6170
|
writer.writeln(
|
|
6139
|
-
` ${writer.wrapInColor(hotkey.key.padEnd(
|
|
6171
|
+
` ${writer.wrapInColor(hotkey.key.padEnd(16), cliCore.CliForegroundColor.Cyan)} ${DIM3}${hotkey.description}${RESET3}`
|
|
6140
6172
|
);
|
|
6141
6173
|
});
|
|
6142
6174
|
}
|
|
@@ -14912,6 +14944,111 @@ ${this.fitLine(` \x1B[31m\u2718 ${message}\x1B[0m`)}\x1B[${this.extraLines}A`
|
|
|
14912
14944
|
}
|
|
14913
14945
|
};
|
|
14914
14946
|
|
|
14947
|
+
// src/lib/input/cli-line-buffer.ts
|
|
14948
|
+
var CliLineBuffer = class {
|
|
14949
|
+
constructor() {
|
|
14950
|
+
this._text = "";
|
|
14951
|
+
this._cursorPosition = 0;
|
|
14952
|
+
}
|
|
14953
|
+
get text() {
|
|
14954
|
+
return this._text;
|
|
14955
|
+
}
|
|
14956
|
+
get cursorPosition() {
|
|
14957
|
+
return this._cursorPosition;
|
|
14958
|
+
}
|
|
14959
|
+
set cursorPosition(value) {
|
|
14960
|
+
this._cursorPosition = Math.max(0, Math.min(value, this._text.length));
|
|
14961
|
+
}
|
|
14962
|
+
insert(str) {
|
|
14963
|
+
this._text = this._text.slice(0, this._cursorPosition) + str + this._text.slice(this._cursorPosition);
|
|
14964
|
+
this._cursorPosition += str.length;
|
|
14965
|
+
}
|
|
14966
|
+
deleteCharBefore() {
|
|
14967
|
+
if (this._cursorPosition > 0) {
|
|
14968
|
+
this._text = this._text.slice(0, this._cursorPosition - 1) + this._text.slice(this._cursorPosition);
|
|
14969
|
+
this._cursorPosition--;
|
|
14970
|
+
}
|
|
14971
|
+
}
|
|
14972
|
+
deleteCharAt() {
|
|
14973
|
+
if (this._cursorPosition < this._text.length) {
|
|
14974
|
+
this._text = this._text.slice(0, this._cursorPosition) + this._text.slice(this._cursorPosition + 1);
|
|
14975
|
+
}
|
|
14976
|
+
}
|
|
14977
|
+
moveCursorLeft() {
|
|
14978
|
+
if (this._cursorPosition > 0) {
|
|
14979
|
+
this._cursorPosition--;
|
|
14980
|
+
}
|
|
14981
|
+
}
|
|
14982
|
+
moveCursorRight() {
|
|
14983
|
+
if (this._cursorPosition < this._text.length) {
|
|
14984
|
+
this._cursorPosition++;
|
|
14985
|
+
}
|
|
14986
|
+
}
|
|
14987
|
+
moveHome() {
|
|
14988
|
+
this._cursorPosition = 0;
|
|
14989
|
+
}
|
|
14990
|
+
moveEnd() {
|
|
14991
|
+
this._cursorPosition = this._text.length;
|
|
14992
|
+
}
|
|
14993
|
+
clear() {
|
|
14994
|
+
this._text = "";
|
|
14995
|
+
this._cursorPosition = 0;
|
|
14996
|
+
}
|
|
14997
|
+
setText(str) {
|
|
14998
|
+
this._text = str;
|
|
14999
|
+
this._cursorPosition = str.length;
|
|
15000
|
+
}
|
|
15001
|
+
/** Remove the text before the cursor (Ctrl+U); returns it */
|
|
15002
|
+
deleteToStart() {
|
|
15003
|
+
const removed = this._text.slice(0, this._cursorPosition);
|
|
15004
|
+
this._text = this._text.slice(this._cursorPosition);
|
|
15005
|
+
this._cursorPosition = 0;
|
|
15006
|
+
return removed;
|
|
15007
|
+
}
|
|
15008
|
+
/** Remove the text from the cursor to the end (Ctrl+K); returns it */
|
|
15009
|
+
deleteToEnd() {
|
|
15010
|
+
const removed = this._text.slice(this._cursorPosition);
|
|
15011
|
+
this._text = this._text.slice(0, this._cursorPosition);
|
|
15012
|
+
return removed;
|
|
15013
|
+
}
|
|
15014
|
+
/** Remove the whitespace-delimited word before the cursor (Ctrl+W); returns it */
|
|
15015
|
+
deleteWordBefore() {
|
|
15016
|
+
let start = this._cursorPosition;
|
|
15017
|
+
while (start > 0 && /\s/.test(this._text[start - 1])) start--;
|
|
15018
|
+
while (start > 0 && !/\s/.test(this._text[start - 1])) start--;
|
|
15019
|
+
const removed = this._text.slice(start, this._cursorPosition);
|
|
15020
|
+
this._text = this._text.slice(0, start) + this._text.slice(this._cursorPosition);
|
|
15021
|
+
this._cursorPosition = start;
|
|
15022
|
+
return removed;
|
|
15023
|
+
}
|
|
15024
|
+
};
|
|
15025
|
+
var HOME_KEYS = ["", "\x1B[H", "\x1BOH", "\x1B[1~", "\x1B[7~"];
|
|
15026
|
+
var END_KEYS = ["", "\x1B[F", "\x1BOF", "\x1B[4~", "\x1B[8~"];
|
|
15027
|
+
var DELETE_KEYS = ["\x1B[3~", ""];
|
|
15028
|
+
function applyEditingKey(buffer, data, killRing) {
|
|
15029
|
+
if (HOME_KEYS.includes(data)) {
|
|
15030
|
+
buffer.moveHome();
|
|
15031
|
+
} else if (END_KEYS.includes(data)) {
|
|
15032
|
+
buffer.moveEnd();
|
|
15033
|
+
} else if (DELETE_KEYS.includes(data)) {
|
|
15034
|
+
buffer.deleteCharAt();
|
|
15035
|
+
} else if (data === "") {
|
|
15036
|
+
killRing.text = buffer.deleteToStart() || killRing.text;
|
|
15037
|
+
} else if (data === "\v") {
|
|
15038
|
+
killRing.text = buffer.deleteToEnd() || killRing.text;
|
|
15039
|
+
} else if (data === "" || data === "\x1B\x7F") {
|
|
15040
|
+
killRing.text = buffer.deleteWordBefore() || killRing.text;
|
|
15041
|
+
} else if (data === "") {
|
|
15042
|
+
if (killRing.text) buffer.insert(killRing.text);
|
|
15043
|
+
} else {
|
|
15044
|
+
return false;
|
|
15045
|
+
}
|
|
15046
|
+
return true;
|
|
15047
|
+
}
|
|
15048
|
+
function isEscapeSequence(data) {
|
|
15049
|
+
return /^\u001b(\[[0-9;?]*[~A-Za-z]|O[A-Za-z])$/.test(data);
|
|
15050
|
+
}
|
|
15051
|
+
|
|
14915
15052
|
// src/lib/input/modes/line-input-mode.ts
|
|
14916
15053
|
var LineInputMode = class extends InputModeBase {
|
|
14917
15054
|
constructor(host, resolve, promptText, options) {
|
|
@@ -14919,6 +15056,7 @@ var LineInputMode = class extends InputModeBase {
|
|
|
14919
15056
|
this.promptText = promptText;
|
|
14920
15057
|
this.options = options;
|
|
14921
15058
|
this.hasError = false;
|
|
15059
|
+
this.killRing = { text: "" };
|
|
14922
15060
|
this.buffer = options?.default ?? "";
|
|
14923
15061
|
this.cursorPosition = this.buffer.length;
|
|
14924
15062
|
}
|
|
@@ -14963,7 +15101,7 @@ var LineInputMode = class extends InputModeBase {
|
|
|
14963
15101
|
this.cursorPosition++;
|
|
14964
15102
|
this.host.terminal.write(data);
|
|
14965
15103
|
}
|
|
14966
|
-
} else if (data.startsWith("\x1B")) ; else {
|
|
15104
|
+
} else if (this.applyEditingKey(data)) ; else if (data.startsWith("\x1B")) ; else {
|
|
14967
15105
|
const text = data.replace(/[\r\n]+/g, "");
|
|
14968
15106
|
this.buffer = this.buffer.slice(0, this.cursorPosition) + text + this.buffer.slice(this.cursorPosition);
|
|
14969
15107
|
this.cursorPosition += text.length;
|
|
@@ -14974,6 +15112,16 @@ var LineInputMode = class extends InputModeBase {
|
|
|
14974
15112
|
}
|
|
14975
15113
|
}
|
|
14976
15114
|
}
|
|
15115
|
+
applyEditingKey(data) {
|
|
15116
|
+
const line2 = new CliLineBuffer();
|
|
15117
|
+
line2.setText(this.buffer);
|
|
15118
|
+
line2.cursorPosition = this.cursorPosition;
|
|
15119
|
+
if (!applyEditingKey(line2, data, this.killRing)) return false;
|
|
15120
|
+
this.buffer = line2.text;
|
|
15121
|
+
this.cursorPosition = line2.cursorPosition;
|
|
15122
|
+
this.renderLine();
|
|
15123
|
+
return true;
|
|
15124
|
+
}
|
|
14977
15125
|
onResize() {
|
|
14978
15126
|
this.renderLine();
|
|
14979
15127
|
}
|
|
@@ -16709,67 +16857,13 @@ var CliCompletionEngine = class {
|
|
|
16709
16857
|
}
|
|
16710
16858
|
};
|
|
16711
16859
|
|
|
16712
|
-
// src/lib/input/cli-line-buffer.ts
|
|
16713
|
-
var CliLineBuffer = class {
|
|
16714
|
-
constructor() {
|
|
16715
|
-
this._text = "";
|
|
16716
|
-
this._cursorPosition = 0;
|
|
16717
|
-
}
|
|
16718
|
-
get text() {
|
|
16719
|
-
return this._text;
|
|
16720
|
-
}
|
|
16721
|
-
get cursorPosition() {
|
|
16722
|
-
return this._cursorPosition;
|
|
16723
|
-
}
|
|
16724
|
-
set cursorPosition(value) {
|
|
16725
|
-
this._cursorPosition = Math.max(0, Math.min(value, this._text.length));
|
|
16726
|
-
}
|
|
16727
|
-
insert(str) {
|
|
16728
|
-
this._text = this._text.slice(0, this._cursorPosition) + str + this._text.slice(this._cursorPosition);
|
|
16729
|
-
this._cursorPosition += str.length;
|
|
16730
|
-
}
|
|
16731
|
-
deleteCharBefore() {
|
|
16732
|
-
if (this._cursorPosition > 0) {
|
|
16733
|
-
this._text = this._text.slice(0, this._cursorPosition - 1) + this._text.slice(this._cursorPosition);
|
|
16734
|
-
this._cursorPosition--;
|
|
16735
|
-
}
|
|
16736
|
-
}
|
|
16737
|
-
deleteCharAt() {
|
|
16738
|
-
if (this._cursorPosition < this._text.length) {
|
|
16739
|
-
this._text = this._text.slice(0, this._cursorPosition) + this._text.slice(this._cursorPosition + 1);
|
|
16740
|
-
}
|
|
16741
|
-
}
|
|
16742
|
-
moveCursorLeft() {
|
|
16743
|
-
if (this._cursorPosition > 0) {
|
|
16744
|
-
this._cursorPosition--;
|
|
16745
|
-
}
|
|
16746
|
-
}
|
|
16747
|
-
moveCursorRight() {
|
|
16748
|
-
if (this._cursorPosition < this._text.length) {
|
|
16749
|
-
this._cursorPosition++;
|
|
16750
|
-
}
|
|
16751
|
-
}
|
|
16752
|
-
moveHome() {
|
|
16753
|
-
this._cursorPosition = 0;
|
|
16754
|
-
}
|
|
16755
|
-
moveEnd() {
|
|
16756
|
-
this._cursorPosition = this._text.length;
|
|
16757
|
-
}
|
|
16758
|
-
clear() {
|
|
16759
|
-
this._text = "";
|
|
16760
|
-
this._cursorPosition = 0;
|
|
16761
|
-
}
|
|
16762
|
-
setText(str) {
|
|
16763
|
-
this._text = str;
|
|
16764
|
-
this._cursorPosition = str.length;
|
|
16765
|
-
}
|
|
16766
|
-
};
|
|
16767
|
-
|
|
16768
16860
|
// src/lib/input/command-line-mode.ts
|
|
16769
16861
|
var CommandLineMode = class {
|
|
16770
16862
|
constructor(host) {
|
|
16771
16863
|
this.host = host;
|
|
16772
16864
|
this.historyIndex = 0;
|
|
16865
|
+
/** History generation `historyIndex` points into (another user's history may be loaded since) */
|
|
16866
|
+
this.historyGeneration = 0;
|
|
16773
16867
|
this.isExecutingCommand = false;
|
|
16774
16868
|
this.selectionStart = null;
|
|
16775
16869
|
this.selectionEnd = null;
|
|
@@ -16785,6 +16879,7 @@ var CommandLineMode = class {
|
|
|
16785
16879
|
* into the command's output and appended to the line just submitted.
|
|
16786
16880
|
*/
|
|
16787
16881
|
this.typeAhead = [];
|
|
16882
|
+
this.killRing = { text: "" };
|
|
16788
16883
|
}
|
|
16789
16884
|
activate() {
|
|
16790
16885
|
this.host.commandHistory.initialize().then(() => {
|
|
@@ -16840,7 +16935,7 @@ var CommandLineMode = class {
|
|
|
16840
16935
|
}
|
|
16841
16936
|
} else if (data === "\x7F") {
|
|
16842
16937
|
this.handleBackspace();
|
|
16843
|
-
} else {
|
|
16938
|
+
} else if (this.applyEditingKey(data)) ; else if (isEscapeSequence(data)) ; else {
|
|
16844
16939
|
this.handleInputText(data);
|
|
16845
16940
|
}
|
|
16846
16941
|
}
|
|
@@ -16938,6 +17033,16 @@ var CommandLineMode = class {
|
|
|
16938
17033
|
} catch {
|
|
16939
17034
|
}
|
|
16940
17035
|
}
|
|
17036
|
+
applyEditingKey(data) {
|
|
17037
|
+
const buffer = this.host.lineBuffer;
|
|
17038
|
+
const before = buffer.text;
|
|
17039
|
+
const previousContentLength = this.host.getPromptLength() + before.length;
|
|
17040
|
+
if (!applyEditingKey(buffer, data, this.killRing)) return false;
|
|
17041
|
+
this.clearGhostText();
|
|
17042
|
+
if (buffer.text !== before) this.clearHistorySearch();
|
|
17043
|
+
this.refreshLine(previousContentLength);
|
|
17044
|
+
return true;
|
|
17045
|
+
}
|
|
16941
17046
|
handleBackspace() {
|
|
16942
17047
|
const buffer = this.host.lineBuffer;
|
|
16943
17048
|
this.clearGhostText();
|
|
@@ -17003,7 +17108,17 @@ var CommandLineMode = class {
|
|
|
17003
17108
|
}
|
|
17004
17109
|
}
|
|
17005
17110
|
}
|
|
17111
|
+
/** Start over at the end when another history was loaded (`su`, `exit`, login) */
|
|
17112
|
+
syncHistory() {
|
|
17113
|
+
const generation = this.host.commandHistory.generation;
|
|
17114
|
+
if (generation === this.historyGeneration) return;
|
|
17115
|
+
this.historyGeneration = generation;
|
|
17116
|
+
this.historySearchPrefix = null;
|
|
17117
|
+
this.bufferSetByHistory = false;
|
|
17118
|
+
this.historyIndex = this.host.commandHistory.getLastIndex();
|
|
17119
|
+
}
|
|
17006
17120
|
showPreviousCommand() {
|
|
17121
|
+
this.syncHistory();
|
|
17007
17122
|
this.clearGhostText();
|
|
17008
17123
|
const buffer = this.host.lineBuffer;
|
|
17009
17124
|
if (buffer.text && !this.bufferSetByHistory && this.historySearchPrefix === null) {
|
|
@@ -17027,6 +17142,7 @@ var CommandLineMode = class {
|
|
|
17027
17142
|
}
|
|
17028
17143
|
}
|
|
17029
17144
|
showNextCommand() {
|
|
17145
|
+
this.syncHistory();
|
|
17030
17146
|
this.clearGhostText();
|
|
17031
17147
|
const buffer = this.host.lineBuffer;
|
|
17032
17148
|
if (this.historySearchPrefix !== null) {
|
|
@@ -17290,6 +17406,7 @@ var CliExecutionContext = class {
|
|
|
17290
17406
|
set userSession(session) {
|
|
17291
17407
|
const previous = this._userSession?.user?.name;
|
|
17292
17408
|
this._userSession = session;
|
|
17409
|
+
void this.commandHistory?.useUser(session?.user?.id);
|
|
17293
17410
|
if (session?.user?.name !== previous) {
|
|
17294
17411
|
this.events?.emit("session:changed", { user: session?.user?.name });
|
|
17295
17412
|
}
|
|
@@ -18862,15 +18979,41 @@ var CliLogger = class {
|
|
|
18862
18979
|
};
|
|
18863
18980
|
|
|
18864
18981
|
// src/lib/services/cli-command-history.ts
|
|
18982
|
+
var SHARED_KEY = "cli-command-history";
|
|
18983
|
+
var MIGRATED_KEY = "cli-command-history:migrated";
|
|
18865
18984
|
var CliCommandHistory = class {
|
|
18866
18985
|
constructor(store) {
|
|
18867
18986
|
this.store = store;
|
|
18868
|
-
this.storageKey = "cli-command-history";
|
|
18869
18987
|
this.commandHistory = [];
|
|
18988
|
+
this.loading = Promise.resolve();
|
|
18989
|
+
/** Counts user switches (a load for an older one is dropped) */
|
|
18990
|
+
this.switches = 0;
|
|
18991
|
+
this._generation = 0;
|
|
18992
|
+
}
|
|
18993
|
+
/** Changes whenever the history is replaced: switched or loaded (positions into it are stale) */
|
|
18994
|
+
get generation() {
|
|
18995
|
+
return this._generation;
|
|
18996
|
+
}
|
|
18997
|
+
get storageKey() {
|
|
18998
|
+
return this.userId === void 0 ? SHARED_KEY : `${SHARED_KEY}:user:${this.userId}`;
|
|
18999
|
+
}
|
|
19000
|
+
/**
|
|
19001
|
+
* Switch to the history of `userId` (undefined: nobody signed in).
|
|
19002
|
+
* Resolves once it is loaded; a no-op for the user already loaded.
|
|
19003
|
+
*/
|
|
19004
|
+
useUser(userId) {
|
|
19005
|
+
if (userId === this.userId) return this.loading;
|
|
19006
|
+
this.userId = userId;
|
|
19007
|
+
this.commandHistory = [];
|
|
19008
|
+
this.switches++;
|
|
19009
|
+
this._generation++;
|
|
19010
|
+
this.loading = this.loadHistory();
|
|
19011
|
+
return this.loading;
|
|
18870
19012
|
}
|
|
18871
19013
|
async addCommand(command2) {
|
|
18872
19014
|
const normalizedCommand = command2.trim();
|
|
18873
19015
|
if (!normalizedCommand) return;
|
|
19016
|
+
await this.loading;
|
|
18874
19017
|
const existingIndex = this.commandHistory.indexOf(normalizedCommand);
|
|
18875
19018
|
if (existingIndex !== -1) {
|
|
18876
19019
|
this.commandHistory.splice(existingIndex, 1);
|
|
@@ -18937,18 +19080,32 @@ var CliCommandHistory = class {
|
|
|
18937
19080
|
return await this.store.set(this.storageKey, trimmedHistory);
|
|
18938
19081
|
}
|
|
18939
19082
|
async loadHistory() {
|
|
18940
|
-
const
|
|
19083
|
+
const key = this.storageKey;
|
|
19084
|
+
const switches = this.switches;
|
|
19085
|
+
const savedOldHistory = typeof localStorage !== "undefined" ? localStorage.getItem("cliCommandHistory") : null;
|
|
18941
19086
|
if (savedOldHistory) {
|
|
18942
19087
|
localStorage.removeItem("cliCommandHistory");
|
|
18943
|
-
await this.store.set(
|
|
19088
|
+
await this.store.set(SHARED_KEY, JSON.parse(savedOldHistory));
|
|
19089
|
+
}
|
|
19090
|
+
let savedHistory = await this.store.get(key);
|
|
19091
|
+
if (!savedHistory && key !== SHARED_KEY && !await this.store.get(MIGRATED_KEY)) {
|
|
19092
|
+
await this.store.set(MIGRATED_KEY, true);
|
|
19093
|
+
const shared = await this.store.get(SHARED_KEY);
|
|
19094
|
+
if (shared?.length) {
|
|
19095
|
+
await this.store.set(key, shared);
|
|
19096
|
+
await this.store.remove(SHARED_KEY);
|
|
19097
|
+
savedHistory = shared;
|
|
19098
|
+
}
|
|
18944
19099
|
}
|
|
18945
|
-
|
|
19100
|
+
if (switches !== this.switches) return;
|
|
18946
19101
|
if (savedHistory) {
|
|
18947
19102
|
this.commandHistory = savedHistory;
|
|
19103
|
+
this._generation++;
|
|
18948
19104
|
}
|
|
18949
19105
|
}
|
|
18950
19106
|
async initialize() {
|
|
18951
|
-
|
|
19107
|
+
this.loading = this.loadHistory();
|
|
19108
|
+
await this.loading;
|
|
18952
19109
|
}
|
|
18953
19110
|
};
|
|
18954
19111
|
var welcomeModule = {
|
|
@@ -22990,6 +23147,9 @@ var CliTestHarness = class {
|
|
|
22990
23147
|
createContext(writer) {
|
|
22991
23148
|
const process = new CliExecutionProcess(null);
|
|
22992
23149
|
const reader = createQueuedReader(this.readerResponses);
|
|
23150
|
+
const provider = this.userSessionProvider;
|
|
23151
|
+
const fallback = this.userSession;
|
|
23152
|
+
const assigned = { set: false };
|
|
22993
23153
|
const context2 = {
|
|
22994
23154
|
writer,
|
|
22995
23155
|
services: this.services,
|
|
@@ -23005,7 +23165,14 @@ var CliTestHarness = class {
|
|
|
23005
23165
|
options: void 0,
|
|
23006
23166
|
logger: createNoopLogger(),
|
|
23007
23167
|
process,
|
|
23008
|
-
|
|
23168
|
+
// Live, like the engine's root context (commands run by a command see changes)
|
|
23169
|
+
get userSession() {
|
|
23170
|
+
return assigned.set ? assigned.value : provider ? provider() : fallback;
|
|
23171
|
+
},
|
|
23172
|
+
set userSession(value) {
|
|
23173
|
+
assigned.set = true;
|
|
23174
|
+
assigned.value = value;
|
|
23175
|
+
},
|
|
23009
23176
|
state: this.stateStoreManager.getStateStore("shared"),
|
|
23010
23177
|
backgroundServices: createNoopBackgroundServices(),
|
|
23011
23178
|
http: new CliHttpClient(),
|