koishi-plugin-terminal 1.0.2 → 1.0.4

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.
@@ -0,0 +1,12 @@
1
+ import { Schema } from "koishi";
2
+ export interface Config {
3
+ admin?: Array<string>;
4
+ auth?: number;
5
+ root?: string;
6
+ shell?: string;
7
+ timeout?: number;
8
+ cols?: number;
9
+ rows?: number;
10
+ maxOutputLength: number;
11
+ }
12
+ export declare const Config: Schema<Config>;
@@ -0,0 +1,4 @@
1
+ export declare function resolveShell(shell?: string): string;
2
+ export declare function getKey(session: any): string;
3
+ export declare function fixNodePtyHelper(): void;
4
+ export declare function isInteractiveCommand(command: string): boolean;
package/lib/index.d.ts CHANGED
@@ -1,16 +1,7 @@
1
- import { Context, Schema } from 'koishi';
1
+ import { Context } from 'koishi';
2
2
  import * as pty from "node-pty";
3
+ import { Config } from "./config";
3
4
  export declare const name = "terminal";
4
- export interface Config {
5
- admin?: Array<string>;
6
- auth?: number;
7
- root?: string;
8
- shell?: string;
9
- timeout?: number;
10
- cols?: number;
11
- rows?: number;
12
- maxOutputLength: number;
13
- }
14
5
  export interface ShellSession {
15
6
  terminal: pty.IPty;
16
7
  buffer: string;
@@ -20,5 +11,4 @@ export interface ShellSession {
20
11
  dispose(): void;
21
12
  }>;
22
13
  }
23
- export declare const Config: Schema<Config>;
24
14
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js CHANGED
@@ -30,7 +30,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
- Config: () => Config,
34
33
  apply: () => apply,
35
34
  name: () => name
36
35
  });
@@ -38,17 +37,33 @@ module.exports = __toCommonJS(src_exports);
38
37
  var import_koishi = require("koishi");
39
38
  var pty = __toESM(require("node-pty"));
40
39
  var import_node_timers = require("node:timers");
41
- var name = "terminal";
42
- var Config = import_koishi.Schema.object({
43
- admin: import_koishi.Schema.array(String).description("超级管理员用户名单").default([]),
44
- auth: import_koishi.Schema.number().description("使用本插件所需的最低权限,此外,用户也需要在超级管理员名单中。").min(1).max(4).step(1).default(4),
45
- root: import_koishi.Schema.string().description("初始工作路径").default(process.env.HOME),
46
- shell: import_koishi.Schema.string().description("Shell路径,留空则自动检测系统默认Shell"),
47
- timeout: import_koishi.Schema.number().description("超时时长").default(import_koishi.Time.minute),
48
- cols: import_koishi.Schema.number().description("终端列数").default(80),
49
- rows: import_koishi.Schema.number().description("终端行数").default(24),
50
- maxOutputLength: import_koishi.Schema.number().description("单次发送最大输出长度").default(16384)
51
- });
40
+
41
+ // src/stripper.ts
42
+ function stripBackspaces(input) {
43
+ const chars = [];
44
+ for (const char of input) {
45
+ if (char === "\b") {
46
+ chars.pop();
47
+ } else {
48
+ chars.push(char);
49
+ }
50
+ }
51
+ return chars.join("");
52
+ }
53
+ __name(stripBackspaces, "stripBackspaces");
54
+ function stripAnsi(input) {
55
+ const text = stripBackspaces(input.replace(
56
+ // eslint-disable-next-line no-control-regex
57
+ /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g,
58
+ ""
59
+ ));
60
+ return text.replace(/\r\n/g, "\n").split("\n").map((line) => line.split("\r").at(-1)).join("\n");
61
+ }
62
+ __name(stripAnsi, "stripAnsi");
63
+
64
+ // src/helper.ts
65
+ var import_node_path = require("node:path");
66
+ var import_node_fs = require("node:fs");
52
67
  function resolveShell(shell) {
53
68
  if (shell) return shell;
54
69
  switch (process.platform) {
@@ -62,28 +77,30 @@ function resolveShell(shell) {
62
77
  return "bash";
63
78
  }
64
79
  __name(resolveShell, "resolveShell");
65
- function stripAnsi(input) {
66
- const text = input.replace(
67
- // eslint-disable-next-line no-control-regex
68
- /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g,
69
- ""
70
- );
71
- return text.replace(/\r\n/g, "\n").split("\n").map((line) => line.split("\r").at(-1)).join("\n");
72
- }
73
- __name(stripAnsi, "stripAnsi");
74
80
  function getKey(session) {
75
81
  return `${session.platform}:${session.userId}`;
76
82
  }
77
83
  __name(getKey, "getKey");
84
+ function fixNodePtyHelper() {
85
+ if (process.platform !== "darwin") return;
86
+ try {
87
+ const root = (0, import_node_path.dirname)(require.resolve("node-pty/package.json"));
88
+ const helper = (0, import_node_path.join)(root, "prebuilds", `darwin-${process.arch}`, "spawn-helper");
89
+ const mode = (0, import_node_fs.statSync)(helper).mode;
90
+ if (!(mode & 73)) (0, import_node_fs.chmodSync)(helper, mode | 493);
91
+ } catch {
92
+ }
93
+ }
94
+ __name(fixNodePtyHelper, "fixNodePtyHelper");
78
95
  function isInteractiveCommand(command) {
79
96
  const trimmed = command.trim();
80
97
  if (!trimmed) return false;
81
98
  const [name2, ...args] = trimmed.split(/\s+/);
82
99
  if (/^(vi|vim|nvim|nano|emacs)$/.test(name2)) return true;
83
- if (/^(less|more|man)$/.test(name2)) return true;
100
+ if (/^(less|more)$/.test(name2)) return true;
84
101
  if (/^(top|htop|btop|watch)$/.test(name2)) return true;
85
102
  if (/^(tmux|screen)$/.test(name2)) return true;
86
- if (/^(ssh|sftp|ftp|telnet)$/.test(name2)) return true;
103
+ if (/^(sftp|ftp|telnet)$/.test(name2)) return true;
87
104
  if (/^(mysql|psql|sqlite3|redis-cli|mongosh)$/.test(name2)) return true;
88
105
  if (/^(node|python|python3|ipython|ruby|irb|php|lua|R)$/.test(name2) && !args.length) return true;
89
106
  if (name2 === "tail" && args.includes("-f")) return true;
@@ -92,8 +109,12 @@ function isInteractiveCommand(command) {
92
109
  return false;
93
110
  }
94
111
  __name(isInteractiveCommand, "isInteractiveCommand");
112
+
113
+ // src/index.ts
114
+ var name = "terminal";
95
115
  var map = /* @__PURE__ */ new Map();
96
116
  function apply(ctx, config) {
117
+ fixNodePtyHelper();
97
118
  const allowedUsers = config.admin;
98
119
  function refreshTimeout(shellSession, key, session) {
99
120
  if (!config.timeout) return;
@@ -120,7 +141,13 @@ function apply(ctx, config) {
120
141
  cols: config.cols,
121
142
  rows: config.rows,
122
143
  cwd: config.root,
123
- env: process.env
144
+ env: {
145
+ ...process.env,
146
+ PAGER: "cat",
147
+ MANPAGER: "cat",
148
+ GIT_PAGER: "cat",
149
+ LESS: "-FRX"
150
+ }
124
151
  });
125
152
  const shellSession = {
126
153
  terminal,
@@ -133,7 +160,7 @@ function apply(ctx, config) {
133
160
  shellSession.buffer = "";
134
161
  if (!output) return;
135
162
  const text = output.length > config.maxOutputLength ? output.slice(0, config.maxOutputLength - 1) + "\n ...Truncated output" : output;
136
- await session.send(text);
163
+ await session.send(import_koishi.h.text(text));
137
164
  }, "flush");
138
165
  const dataDisposable = terminal.onData((data) => {
139
166
  shellSession.buffer += data;
@@ -165,7 +192,7 @@ function apply(ctx, config) {
165
192
  }
166
193
  }
167
194
  __name(cleanupSession, "cleanupSession");
168
- ctx.command("shell [command:text]", "Start a persistent shell session", { authority: config.auth }).option("terminate", "-t Terminate current shell session").usage("After start up, regular user messages will be sent to shell process.").example("shell echo Operating System: Three Easy Pieces > qljj.txt").action(async ({ session, options }, command) => {
195
+ ctx.command("shell [command:text]", "Start a persistent shell session.", { authority: config.auth }).option("terminate", "-t Terminate current shell session").usage("After start up, user messages will be sent to shell process.").example("shell echo Operating System: Three Easy Pieces > qljj.txt").action(async ({ session, options }, command) => {
169
196
  if (!allowedUsers.includes(session.userId)) {
170
197
  return "Unauthorized user.";
171
198
  }
@@ -208,7 +235,6 @@ function apply(ctx, config) {
208
235
  __name(apply, "apply");
209
236
  // Annotate the CommonJS export names for ESM import in node:
210
237
  0 && (module.exports = {
211
- Config,
212
238
  apply,
213
239
  name
214
240
  });
@@ -0,0 +1,2 @@
1
+ export declare function stripBackspaces(input: string): string;
2
+ export declare function stripAnsi(input: string): string;
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "koishi-plugin-terminal",
3
3
  "description": "通过 QQ 运行持久的 Shell 终端",
4
- "version": "1.0.2",
4
+ "version": "1.0.4",
5
5
  "main": "lib/index.js",
6
+ "author": {
7
+ "email": "ygong68@wisc.edu",
8
+ "name": "Jingmozhiyu"
9
+ },
6
10
  "typings": "lib/index.d.ts",
7
11
  "files": [
8
12
  "lib",