pty-shell 1.4.0 → 1.5.1
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/dist/index.d.ts +5 -0
- package/dist/index.js +218 -109
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -122,6 +122,11 @@ export declare class PtyShell implements PtyShellUserMethod {
|
|
|
122
122
|
private push_history_line;
|
|
123
123
|
private exec_end_call;
|
|
124
124
|
private parse_exec;
|
|
125
|
+
/**
|
|
126
|
+
* 解析组合命令,按 ; && || 分隔,返回命令列表
|
|
127
|
+
* 支持引号内的分隔符不被拆分
|
|
128
|
+
*/
|
|
129
|
+
private parse_combined_commands;
|
|
125
130
|
private multiple_line;
|
|
126
131
|
private spawn_write;
|
|
127
132
|
private spawn;
|
package/dist/index.js
CHANGED
|
@@ -767,16 +767,24 @@ class PtyShell {
|
|
|
767
767
|
this.clear_line();
|
|
768
768
|
return;
|
|
769
769
|
}
|
|
770
|
-
let { exe, params } = this.get_exec(this.line);
|
|
771
770
|
this.history_line_index = -1;
|
|
772
|
-
|
|
771
|
+
// 解析组合命令(支持 ; && ||),解析出的 exe_cmd/params 来自 get_exec
|
|
772
|
+
const commands = this.parse_combined_commands(this.line);
|
|
773
|
+
if (commands.length === 0) {
|
|
774
|
+
this.send_and_enter("");
|
|
775
|
+
this.clear_line();
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
const resolved_list = [];
|
|
779
|
+
for (const cmd of commands) {
|
|
780
|
+
let { exe_cmd, params } = cmd;
|
|
773
781
|
let use_noe_pty = false;
|
|
782
|
+
// 1. check_exe_cmd(只调一次)
|
|
774
783
|
if (this.check_exe_cmd) {
|
|
775
|
-
|
|
776
|
-
const v = yield this.check_exe_cmd(exe, params);
|
|
784
|
+
const v = yield this.check_exe_cmd(exe_cmd, params);
|
|
777
785
|
switch (v) {
|
|
778
786
|
case exec_type.not:
|
|
779
|
-
this.send_and_enter(`not have permission to execute ${
|
|
787
|
+
this.send_and_enter(`not have permission to execute ${exe_cmd}`);
|
|
780
788
|
this.clear_line();
|
|
781
789
|
this.exec_end_call(-1);
|
|
782
790
|
return;
|
|
@@ -791,43 +799,136 @@ class PtyShell {
|
|
|
791
799
|
return;
|
|
792
800
|
}
|
|
793
801
|
}
|
|
802
|
+
// 2. cmd_replace(只调一次)
|
|
794
803
|
if (this.cmd_replace) {
|
|
795
|
-
const r = yield this.cmd_replace(
|
|
796
|
-
|
|
804
|
+
const r = yield this.cmd_replace(exe_cmd, params);
|
|
805
|
+
exe_cmd = r.exe_cmd;
|
|
797
806
|
params = r.params;
|
|
798
807
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
808
|
+
resolved_list.push({
|
|
809
|
+
exe_cmd,
|
|
810
|
+
params,
|
|
811
|
+
separator: cmd.separator,
|
|
812
|
+
use_noe_pty,
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
// 全部校验通过,按分隔符语义串行执行
|
|
816
|
+
let lastExitCode = 0;
|
|
817
|
+
for (let i = 0; i < resolved_list.length; i++) {
|
|
818
|
+
const cmd = resolved_list[i];
|
|
819
|
+
// 根据前一个命令的退出码和分隔符决定是否跳过当前命令
|
|
820
|
+
if (i > 0) {
|
|
821
|
+
const prevSep = resolved_list[i - 1].separator;
|
|
822
|
+
if (prevSep === '&&' && lastExitCode !== 0)
|
|
823
|
+
continue; // 前面失败,跳过
|
|
824
|
+
if (prevSep === '||' && lastExitCode === 0)
|
|
825
|
+
continue; // 前面成功,跳过
|
|
806
826
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
827
|
+
try {
|
|
828
|
+
if (this.cmd_exec_map.has(cmd.exe_cmd)) {
|
|
829
|
+
yield this.exec_cmd(cmd.exe_cmd, cmd.params);
|
|
830
|
+
lastExitCode = 0;
|
|
831
|
+
}
|
|
832
|
+
else if (this.js_child_map.has(cmd.exe_cmd)) {
|
|
833
|
+
// js_child 异步模式,不支持在组合命令中等待
|
|
834
|
+
if (resolved_list.length > 1) {
|
|
835
|
+
this.send_and_enter(`\x1b[31mjs_child not supported in combined commands: ${cmd.exe_cmd}\x1b[0m`);
|
|
836
|
+
lastExitCode = -1;
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
839
|
+
const c_ = this.js_child_map.get(cmd.exe_cmd);
|
|
840
|
+
this.js_func_child = new c_(this, () => {
|
|
841
|
+
this.send_and_enter("", true);
|
|
842
|
+
this.next_not_enter = false;
|
|
843
|
+
this.close_child();
|
|
844
|
+
}, (str) => {
|
|
845
|
+
this.send_and_enter(str);
|
|
846
|
+
}, cmd.params);
|
|
847
|
+
this.js_func_child.init();
|
|
848
|
+
this.clear_line();
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
// 子进程:组合命令需要同步等待,单命令走原有异步
|
|
853
|
+
lastExitCode = yield this.spawn(cmd.exe_cmd, cmd.params, cmd.use_noe_pty);
|
|
854
|
+
}
|
|
818
855
|
}
|
|
819
|
-
|
|
820
|
-
this.
|
|
856
|
+
catch (e) {
|
|
857
|
+
this.send_and_enter((_a = e.message) !== null && _a !== void 0 ? _a : e);
|
|
858
|
+
lastExitCode = -1;
|
|
821
859
|
}
|
|
822
|
-
this.clear_line();
|
|
823
|
-
}
|
|
824
|
-
catch (e) {
|
|
825
|
-
// console.log("子线程执行异常", e);
|
|
826
|
-
this.send_and_enter((_a = e.message) !== null && _a !== void 0 ? _a : e);
|
|
827
|
-
this.exec_end_call(-1);
|
|
828
860
|
}
|
|
861
|
+
this.clear_line();
|
|
862
|
+
this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
|
|
863
|
+
this.close_child(lastExitCode);
|
|
829
864
|
});
|
|
830
865
|
}
|
|
866
|
+
/**
|
|
867
|
+
* 解析组合命令,按 ; && || 分隔,返回命令列表
|
|
868
|
+
* 支持引号内的分隔符不被拆分
|
|
869
|
+
*/
|
|
870
|
+
parse_combined_commands(line) {
|
|
871
|
+
const result = [];
|
|
872
|
+
let current = '';
|
|
873
|
+
let quote = null;
|
|
874
|
+
let i = 0;
|
|
875
|
+
while (i < line.length) {
|
|
876
|
+
const ch = line[i];
|
|
877
|
+
if (ch === '"' || ch === "'") {
|
|
878
|
+
if (quote === null) {
|
|
879
|
+
quote = ch;
|
|
880
|
+
}
|
|
881
|
+
else if (quote === ch) {
|
|
882
|
+
quote = null;
|
|
883
|
+
}
|
|
884
|
+
current += ch;
|
|
885
|
+
i++;
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
if (quote !== null) {
|
|
889
|
+
current += ch;
|
|
890
|
+
i++;
|
|
891
|
+
continue;
|
|
892
|
+
}
|
|
893
|
+
// &&
|
|
894
|
+
if (ch === '&' && i + 1 < line.length && line[i + 1] === '&') {
|
|
895
|
+
if (current.trim()) {
|
|
896
|
+
const r = this.get_exec(current.trim());
|
|
897
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '&&' });
|
|
898
|
+
current = '';
|
|
899
|
+
}
|
|
900
|
+
i += 2;
|
|
901
|
+
continue;
|
|
902
|
+
}
|
|
903
|
+
// ||
|
|
904
|
+
if (ch === '|' && i + 1 < line.length && line[i + 1] === '|') {
|
|
905
|
+
if (current.trim()) {
|
|
906
|
+
const r = this.get_exec(current.trim());
|
|
907
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '||' });
|
|
908
|
+
current = '';
|
|
909
|
+
}
|
|
910
|
+
i += 2;
|
|
911
|
+
continue;
|
|
912
|
+
}
|
|
913
|
+
// ;
|
|
914
|
+
if (ch === ';') {
|
|
915
|
+
if (current.trim()) {
|
|
916
|
+
const r = this.get_exec(current.trim());
|
|
917
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: ';' });
|
|
918
|
+
current = '';
|
|
919
|
+
}
|
|
920
|
+
i++;
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
current += ch;
|
|
924
|
+
i++;
|
|
925
|
+
}
|
|
926
|
+
if (current.trim()) {
|
|
927
|
+
const r = this.get_exec(current.trim());
|
|
928
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '' });
|
|
929
|
+
}
|
|
930
|
+
return result;
|
|
931
|
+
}
|
|
831
932
|
multiple_line(data, enter_index) {
|
|
832
933
|
return __awaiter(this, void 0, void 0, function* () {
|
|
833
934
|
if (!data)
|
|
@@ -862,86 +963,94 @@ class PtyShell {
|
|
|
862
963
|
this.js_func_child.write(str);
|
|
863
964
|
}
|
|
864
965
|
}
|
|
865
|
-
spawn(
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
// this.send_and_enter(""); //
|
|
871
|
-
// if (!this.child) {
|
|
872
|
-
// this.on_call(`\n\r`); // 先换个行
|
|
873
|
-
// }
|
|
874
|
-
if ((use_noe_pty || this.shell_set.has("*") || this.shell_set.has(exe)) && this.node_pty) {
|
|
875
|
-
// if (!exe.includes('exe') && exe !== 'bash' && exe !== 'sh') {
|
|
876
|
-
// exe += '.exe';
|
|
966
|
+
spawn(exe_1, params_1) {
|
|
967
|
+
return __awaiter(this, arguments, void 0, function* (exe, params, use_noe_pty = true) {
|
|
968
|
+
// if (this.not_use_node_pre_cmd_exec) {
|
|
969
|
+
// this.send_and_enter(`not_use_node_pre_cmd_exec is true`);
|
|
970
|
+
// return;
|
|
877
971
|
// }
|
|
878
|
-
this.
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
// maxBuffer: 1024 * 1024 * 10// 设置缓冲区为 10 MB
|
|
912
|
-
});
|
|
913
|
-
// 设置编码为 'utf8',确保输出按 UTF-8 编码解析
|
|
914
|
-
this.child.stdout.setEncoding('utf8');
|
|
915
|
-
this.child.stdout.on('data', (data) => {
|
|
916
|
-
// const v = data.toString(); // 子程序没有换行等符号不会立即输出 有缓冲区
|
|
917
|
-
this.send_and_enter(data.toString());
|
|
918
|
-
if (this.on_call_child_raw) {
|
|
919
|
-
this.on_call_child_raw(data);
|
|
972
|
+
// this.send_and_enter(""); //
|
|
973
|
+
// if (!this.child) {
|
|
974
|
+
// this.on_call(`\n\r`); // 先换个行
|
|
975
|
+
// }
|
|
976
|
+
return new Promise(resolve => {
|
|
977
|
+
if ((use_noe_pty || this.shell_set.has("*") || this.shell_set.has(exe)) && this.node_pty) {
|
|
978
|
+
// if (!exe.includes('exe') && exe !== 'bash' && exe !== 'sh') {
|
|
979
|
+
// exe += '.exe';
|
|
980
|
+
// }
|
|
981
|
+
this.on_call(`\n\r`); // 先换个行
|
|
982
|
+
this.node_pty_child = this.node_pty.spawn(exe, params, {
|
|
983
|
+
name: 'xterm-color',
|
|
984
|
+
cols: this.cols,
|
|
985
|
+
rows: this.rows,
|
|
986
|
+
cwd: this.cwd, // 设置子进程的工作目录
|
|
987
|
+
useConptyDll: false,
|
|
988
|
+
useConpty: process.env.NODE_ENV !== "production" ? false : undefined, // conpty 可以支持 bash 等命令 从 Windows 10 版本 1809 开始提供 , 但是如果使用了 powershell 这个也就没有必要了,而且设置为false才能使用debug模式运行
|
|
989
|
+
env: Object.assign(Object.assign({}, process.env), this.env), // 传递环境变量
|
|
990
|
+
});
|
|
991
|
+
this.node_pty_child.onData((data) => {
|
|
992
|
+
this.on_call(data.toString());
|
|
993
|
+
if (this.on_call_child_raw) {
|
|
994
|
+
this.on_call_child_raw(data);
|
|
995
|
+
}
|
|
996
|
+
});
|
|
997
|
+
this.node_pty_child.onExit(({ exitCode, signal }) => {
|
|
998
|
+
// this.close_child(exitCode);
|
|
999
|
+
// this.send_and_enter("");
|
|
1000
|
+
this.send_and_enter(`pty with ${exitCode}`);
|
|
1001
|
+
// this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
|
|
1002
|
+
resolve(exitCode !== null && exitCode !== void 0 ? exitCode : -1);
|
|
1003
|
+
});
|
|
1004
|
+
// this.is_pty = true;
|
|
920
1005
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1006
|
+
else {
|
|
1007
|
+
// this.is_pty = false;
|
|
1008
|
+
// 其他的没有必要再创建一个 tty 都是资源消耗
|
|
1009
|
+
this.child = child_process.spawn(exe, params, {
|
|
1010
|
+
// shell:getShell(),
|
|
1011
|
+
cwd: this.cwd, // 设置子进程的工作目录
|
|
1012
|
+
env: Object.assign(Object.assign(Object.assign({}, process.env), this.env), { LANG: 'en_US.UTF-8' }), // 传递环境变量
|
|
1013
|
+
// stdio: 'inherit' // 让子进程的输入输出与父进程共享 pipe ignore inherit
|
|
1014
|
+
// timeout: 5000, // 设置超时为 5 秒
|
|
1015
|
+
// maxBuffer: 1024 * 1024 * 10// 设置缓冲区为 10 MB
|
|
1016
|
+
});
|
|
1017
|
+
// 设置编码为 'utf8',确保输出按 UTF-8 编码解析
|
|
1018
|
+
this.child.stdout.setEncoding('utf8');
|
|
1019
|
+
this.child.stdout.on('data', (data) => {
|
|
1020
|
+
// const v = data.toString(); // 子程序没有换行等符号不会立即输出 有缓冲区
|
|
1021
|
+
this.send_and_enter(data.toString());
|
|
1022
|
+
if (this.on_call_child_raw) {
|
|
1023
|
+
this.on_call_child_raw(data);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
this.child.stderr.on('data', (data) => {
|
|
1027
|
+
// const v = data.toString();
|
|
1028
|
+
this.send_and_enter(data.toString());
|
|
1029
|
+
this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
|
|
1030
|
+
if (this.on_call_child_raw) {
|
|
1031
|
+
this.on_call_child_raw(data);
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
this.child.on('exit', (code) => {
|
|
1035
|
+
// this.close_child(code);
|
|
1036
|
+
// if (code !== 1) {
|
|
1037
|
+
this.send_and_enter(`process exited with code ${code}`);
|
|
1038
|
+
// }
|
|
1039
|
+
// else {
|
|
1040
|
+
// this.send_and_enter(``);
|
|
1041
|
+
// }
|
|
1042
|
+
// this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
|
|
1043
|
+
resolve(code !== null && code !== void 0 ? code : -1);
|
|
1044
|
+
});
|
|
1045
|
+
this.child.on('error', (error) => {
|
|
1046
|
+
// this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
|
|
1047
|
+
// this.close_child(-1);
|
|
1048
|
+
this.send_and_enter(error.message);
|
|
1049
|
+
resolve(-1);
|
|
1050
|
+
});
|
|
928
1051
|
}
|
|
929
1052
|
});
|
|
930
|
-
|
|
931
|
-
this.close_child(code);
|
|
932
|
-
// if (code !== 1) {
|
|
933
|
-
// this.send_and_enter(`process exited with code ${code}`);
|
|
934
|
-
// } else {
|
|
935
|
-
this.send_and_enter(``);
|
|
936
|
-
// }
|
|
937
|
-
this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
|
|
938
|
-
});
|
|
939
|
-
this.child.on('error', (error) => {
|
|
940
|
-
this.next_not_enter = false; // 下一次的换行输出 上一次没有换行
|
|
941
|
-
this.close_child(-1);
|
|
942
|
-
this.send_and_enter(error.message);
|
|
943
|
-
});
|
|
944
|
-
}
|
|
1053
|
+
});
|
|
945
1054
|
}
|
|
946
1055
|
exec_cmd(exe, params) {
|
|
947
1056
|
return __awaiter(this, void 0, void 0, function* () {
|