pty-shell 1.4.0 → 1.5.0
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 +9 -0
- package/dist/index.js +203 -46
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -122,6 +122,15 @@ 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;
|
|
130
|
+
/**
|
|
131
|
+
* 同步方式执行子进程(用于组合命令),返回退出码
|
|
132
|
+
*/
|
|
133
|
+
private spawn_sync;
|
|
125
134
|
private multiple_line;
|
|
126
135
|
private spawn_write;
|
|
127
136
|
private spawn;
|
package/dist/index.js
CHANGED
|
@@ -767,64 +767,221 @@ 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
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
break;
|
|
785
|
-
case exec_type.not_pty:
|
|
786
|
-
use_noe_pty = true;
|
|
787
|
-
break;
|
|
788
|
-
default:
|
|
789
|
-
// 未知的不报错也不执行
|
|
790
|
-
this.exec_end_call(0);
|
|
791
|
-
return;
|
|
784
|
+
const v = yield this.check_exe_cmd(exe_cmd, params);
|
|
785
|
+
if (v === exec_type.not) {
|
|
786
|
+
this.send_and_enter(`not have permission to execute ${exe_cmd}`);
|
|
787
|
+
this.clear_line();
|
|
788
|
+
this.exec_end_call(-1);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
if (v === exec_type.not_pty) {
|
|
792
|
+
use_noe_pty = true;
|
|
792
793
|
}
|
|
793
794
|
}
|
|
795
|
+
// 2. cmd_replace(只调一次)
|
|
794
796
|
if (this.cmd_replace) {
|
|
795
|
-
const r = yield this.cmd_replace(
|
|
796
|
-
|
|
797
|
+
const r = yield this.cmd_replace(exe_cmd, params);
|
|
798
|
+
exe_cmd = r.exe_cmd;
|
|
797
799
|
params = r.params;
|
|
798
800
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
801
|
+
resolved_list.push({
|
|
802
|
+
exe_cmd,
|
|
803
|
+
params,
|
|
804
|
+
separator: cmd.separator,
|
|
805
|
+
use_noe_pty,
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
// 全部校验通过,按分隔符语义串行执行
|
|
809
|
+
let lastExitCode = 0;
|
|
810
|
+
for (let i = 0; i < resolved_list.length; i++) {
|
|
811
|
+
const cmd = resolved_list[i];
|
|
812
|
+
// 根据前一个命令的退出码和分隔符决定是否跳过当前命令
|
|
813
|
+
if (i > 0) {
|
|
814
|
+
const prevSep = resolved_list[i - 1].separator;
|
|
815
|
+
if (prevSep === '&&' && lastExitCode !== 0)
|
|
816
|
+
continue; // 前面失败,跳过
|
|
817
|
+
if (prevSep === '||' && lastExitCode === 0)
|
|
818
|
+
continue; // 前面成功,跳过
|
|
806
819
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
820
|
+
try {
|
|
821
|
+
if (this.cmd_exec_map.has(cmd.exe_cmd)) {
|
|
822
|
+
yield this.exec_cmd(cmd.exe_cmd, cmd.params);
|
|
823
|
+
lastExitCode = 0;
|
|
824
|
+
}
|
|
825
|
+
else if (this.js_child_map.has(cmd.exe_cmd)) {
|
|
826
|
+
// js_child 异步模式,不支持在组合命令中等待
|
|
827
|
+
if (resolved_list.length > 1) {
|
|
828
|
+
this.send_and_enter(`\x1b[31mjs_child not supported in combined commands: ${cmd.exe_cmd}\x1b[0m`);
|
|
829
|
+
lastExitCode = -1;
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
const c_ = this.js_child_map.get(cmd.exe_cmd);
|
|
833
|
+
this.js_func_child = new c_(this, () => {
|
|
834
|
+
this.send_and_enter("", true);
|
|
835
|
+
this.next_not_enter = false;
|
|
836
|
+
this.close_child();
|
|
837
|
+
}, (str) => {
|
|
838
|
+
this.send_and_enter(str);
|
|
839
|
+
}, cmd.params);
|
|
840
|
+
this.js_func_child.init();
|
|
841
|
+
this.clear_line();
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
// 子进程:组合命令需要同步等待,单命令走原有异步
|
|
846
|
+
if (resolved_list.length > 1) {
|
|
847
|
+
lastExitCode = yield this.spawn_sync(cmd.exe_cmd, cmd.params, cmd.use_noe_pty);
|
|
848
|
+
}
|
|
849
|
+
else {
|
|
850
|
+
this.spawn(cmd.exe_cmd, cmd.params, cmd.use_noe_pty);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
818
853
|
}
|
|
819
|
-
|
|
820
|
-
this.
|
|
854
|
+
catch (e) {
|
|
855
|
+
this.send_and_enter((_a = e.message) !== null && _a !== void 0 ? _a : e);
|
|
856
|
+
lastExitCode = -1;
|
|
821
857
|
}
|
|
822
|
-
this.clear_line();
|
|
823
858
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
this.
|
|
827
|
-
|
|
859
|
+
this.clear_line();
|
|
860
|
+
if (commands.length === 1) {
|
|
861
|
+
this.exec_end_call(lastExitCode === 0 ? 0 : -1);
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* 解析组合命令,按 ; && || 分隔,返回命令列表
|
|
867
|
+
* 支持引号内的分隔符不被拆分
|
|
868
|
+
*/
|
|
869
|
+
parse_combined_commands(line) {
|
|
870
|
+
const result = [];
|
|
871
|
+
let current = '';
|
|
872
|
+
let quote = null;
|
|
873
|
+
let i = 0;
|
|
874
|
+
while (i < line.length) {
|
|
875
|
+
const ch = line[i];
|
|
876
|
+
if (ch === '"' || ch === "'") {
|
|
877
|
+
if (quote === null) {
|
|
878
|
+
quote = ch;
|
|
879
|
+
}
|
|
880
|
+
else if (quote === ch) {
|
|
881
|
+
quote = null;
|
|
882
|
+
}
|
|
883
|
+
current += ch;
|
|
884
|
+
i++;
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
if (quote !== null) {
|
|
888
|
+
current += ch;
|
|
889
|
+
i++;
|
|
890
|
+
continue;
|
|
891
|
+
}
|
|
892
|
+
// &&
|
|
893
|
+
if (ch === '&' && i + 1 < line.length && line[i + 1] === '&') {
|
|
894
|
+
if (current.trim()) {
|
|
895
|
+
const r = this.get_exec(current.trim());
|
|
896
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '&&' });
|
|
897
|
+
current = '';
|
|
898
|
+
}
|
|
899
|
+
i += 2;
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
// ||
|
|
903
|
+
if (ch === '|' && i + 1 < line.length && line[i + 1] === '|') {
|
|
904
|
+
if (current.trim()) {
|
|
905
|
+
const r = this.get_exec(current.trim());
|
|
906
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '||' });
|
|
907
|
+
current = '';
|
|
908
|
+
}
|
|
909
|
+
i += 2;
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
// ;
|
|
913
|
+
if (ch === ';') {
|
|
914
|
+
if (current.trim()) {
|
|
915
|
+
const r = this.get_exec(current.trim());
|
|
916
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: ';' });
|
|
917
|
+
current = '';
|
|
918
|
+
}
|
|
919
|
+
i++;
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
current += ch;
|
|
923
|
+
i++;
|
|
924
|
+
}
|
|
925
|
+
if (current.trim()) {
|
|
926
|
+
const r = this.get_exec(current.trim());
|
|
927
|
+
result.push({ exe_cmd: r.exe, params: r.params, separator: '' });
|
|
928
|
+
}
|
|
929
|
+
return result;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* 同步方式执行子进程(用于组合命令),返回退出码
|
|
933
|
+
*/
|
|
934
|
+
spawn_sync(exe, params, use_noe_pty = false) {
|
|
935
|
+
return new Promise((resolve) => {
|
|
936
|
+
var _a, _b;
|
|
937
|
+
if ((use_noe_pty || ((_a = this.shell_set) === null || _a === void 0 ? void 0 : _a.has("*")) || ((_b = this.shell_set) === null || _b === void 0 ? void 0 : _b.has(exe))) && this.node_pty) {
|
|
938
|
+
this.on_call(`\n\r`);
|
|
939
|
+
this.node_pty_child = this.node_pty.spawn(exe, params, {
|
|
940
|
+
name: 'xterm-color',
|
|
941
|
+
cols: this.cols,
|
|
942
|
+
rows: this.rows,
|
|
943
|
+
cwd: this.cwd,
|
|
944
|
+
useConptyDll: false,
|
|
945
|
+
useConpty: process.env.NODE_ENV !== "production" ? false : undefined,
|
|
946
|
+
env: Object.assign(Object.assign({}, process.env), this.env),
|
|
947
|
+
});
|
|
948
|
+
this.node_pty_child.onData((data) => {
|
|
949
|
+
this.on_call(data.toString());
|
|
950
|
+
if (this.on_call_child_raw) {
|
|
951
|
+
this.on_call_child_raw(data);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
this.node_pty_child.onExit(({ exitCode, signal }) => {
|
|
955
|
+
this.node_pty_child = null;
|
|
956
|
+
resolve(exitCode !== null && exitCode !== void 0 ? exitCode : -1);
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
const child = child_process.spawn(exe, params, {
|
|
961
|
+
cwd: this.cwd,
|
|
962
|
+
env: Object.assign(Object.assign({}, process.env), this.env),
|
|
963
|
+
});
|
|
964
|
+
child.stdout.setEncoding('utf8');
|
|
965
|
+
child.stdout.on('data', (data) => {
|
|
966
|
+
this.send_and_enter(data.toString());
|
|
967
|
+
if (this.on_call_child_raw) {
|
|
968
|
+
this.on_call_child_raw(data);
|
|
969
|
+
}
|
|
970
|
+
});
|
|
971
|
+
child.stderr.on('data', (data) => {
|
|
972
|
+
this.send_and_enter(data.toString());
|
|
973
|
+
this.next_not_enter = false;
|
|
974
|
+
if (this.on_call_child_raw) {
|
|
975
|
+
this.on_call_child_raw(data);
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
child.on('exit', (code) => {
|
|
979
|
+
resolve(code !== null && code !== void 0 ? code : -1);
|
|
980
|
+
});
|
|
981
|
+
child.on('error', (error) => {
|
|
982
|
+
this.send_and_enter(error.message);
|
|
983
|
+
resolve(-1);
|
|
984
|
+
});
|
|
828
985
|
}
|
|
829
986
|
});
|
|
830
987
|
}
|