koishi-plugin-freekill-u 1.0.1 → 1.0.2

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.
Files changed (2) hide show
  1. package/lib/index.js +540 -55
  2. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  };
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
 
19
- // src/index.ts
19
+ // packages/freekill-u/src/index.ts
20
20
  var src_exports = {};
21
21
  __export(src_exports, {
22
22
  Config: () => Config,
@@ -29,40 +29,76 @@ var import_koishi = require("koishi");
29
29
  var { Client } = require("ssh2");
30
30
  var name = "freekill-u";
31
31
  var Config = import_koishi.Schema.object({
32
- host: import_koishi.Schema.string().description("SSH \u670D\u52A1\u5668 IP").default(""),
33
- port: import_koishi.Schema.number().description("SSH \u7AEF\u53E3").default(22).min(1).max(65535),
34
- username: import_koishi.Schema.string().description("SSH \u7528\u6237\u540D").default(""),
35
- password: import_koishi.Schema.string().role("secret").description("SSH \u5BC6\u7801").default(""),
36
- screenSession: import_koishi.Schema.string().description("screen \u4F1A\u8BDD\u6807\u8BC6\uFF08\u591A\u4E2A screen \u65F6\u586B\u5199\uFF0C\u5982 1234 \u6216 freekill\uFF1B\u7559\u7A7A\u5219\u7528 screen -r \u9ED8\u8BA4\u9009\u62E9\uFF09").default(""),
37
- updateCommand: import_koishi.Schema.string().description("\u66F4\u65B0\u547D\u4EE4\uFF08\u5728\u65B0\u6708\u6740\u547D\u4EE4\u884C\u8F93\u5165\u7684\u6307\u4EE4\uFF09").default("u"),
38
- attachDelay: import_koishi.Schema.number().description("screen -r \u540E\u7B49\u5F85 attach \u7684\u6BEB\u79D2\u6570").default(3e3).min(500).max(3e4),
39
- updateWait: import_koishi.Schema.number().description("\u53D1\u9001\u66F4\u65B0\u547D\u4EE4\u540E\u7B49\u5F85\u8F93\u51FA\u7684\u6BEB\u79D2\u6570").default(3e4).min(5e3).max(3e5),
40
- authority: import_koishi.Schema.number().description("\u4F7F\u7528\u8BE5\u547D\u4EE4\u6240\u9700\u7684\u6700\u4F4E\u6743\u9650\u7B49\u7EA7").default(4).min(1).max(5),
32
+ servers: import_koishi.Schema.array(import_koishi.Schema.object({
33
+ name: import_koishi.Schema.string().description('\u670D\u52A1\u5668\u540D\u79F0\uFF08\u7528\u4F5C\u547D\u4EE4\u524D\u7F00\uFF0C\u5982"\u5B98\u670D"\u5219\u547D\u4EE4\u4E3A \u5B98\u670D.u / \u5B98\u670D.stat \u7B49\uFF09').required(),
34
+ host: import_koishi.Schema.string().description("SSH \u670D\u52A1\u5668 IP").default(""),
35
+ port: import_koishi.Schema.number().description("SSH \u7AEF\u53E3").default(22).min(1).max(65535),
36
+ username: import_koishi.Schema.string().description("SSH \u7528\u6237\u540D").default(""),
37
+ password: import_koishi.Schema.string().role("secret").description("SSH \u5BC6\u7801").default(""),
38
+ screenSession: import_koishi.Schema.string().description("screen \u4F1A\u8BDD\u6807\u8BC6\uFF08\u591A\u4E2A screen \u65F6\u586B\u5199\uFF0C\u7559\u7A7A\u5219\u7528 screen -r \u9ED8\u8BA4\u9009\u62E9\uFF09").default(""),
39
+ updateCommand: import_koishi.Schema.string().description("\u66F4\u65B0\u547D\u4EE4\uFF08\u5728\u65B0\u6708\u6740\u547D\u4EE4\u884C\u8F93\u5165\u7684\u6307\u4EE4\uFF09").default("u"),
40
+ operators: import_koishi.Schema.string().description("\u64CD\u4F5C\u5458 QQ \u53F7\u767D\u540D\u5355\uFF08\u591A\u4E2A\u7528\u9017\u53F7/\u7A7A\u683C\u5206\u9694\uFF0C\u7559\u7A7A\u5219\u4E0D\u9650\u5236\uFF09\u3002\u4E0D\u5728\u767D\u540D\u5355\u5185\u7684\u7528\u6237\u6267\u884C\u547D\u4EE4\u65F6\u9759\u9ED8\u5FFD\u7565").default(""),
41
+ attachDelay: import_koishi.Schema.number().description("screen -r \u540E\u7B49\u5F85 attach \u7684\u6BEB\u79D2\u6570").default(3e3).min(500).max(3e4),
42
+ updateWait: import_koishi.Schema.number().description("\u53D1\u9001\u66F4\u65B0\u547D\u4EE4\u540E\u7B49\u5F85\u8F93\u51FA\u7684\u6BEB\u79D2\u6570").default(3e4).min(5e3).max(3e5),
43
+ quitWait: import_koishi.Schema.number().description("\u53D1\u9001 quit \u540E\u7B49\u5F85\u670D\u52A1\u5668\u5173\u95ED\u7684\u6BEB\u79D2\u6570").default(5e3).min(2e3).max(6e4),
44
+ restartWait: import_koishi.Schema.number().description("\u53D1\u9001\u542F\u52A8\u547D\u4EE4\u540E\u7B49\u5F85\u670D\u52A1\u5668\u542F\u52A8\u7684\u6BEB\u79D2\u6570").default(6e4).min(1e4).max(3e5),
45
+ commandWait: import_koishi.Schema.number().description("\u666E\u901A\u67E5\u8BE2\u547D\u4EE4\u7B49\u5F85\u8F93\u51FA\u7684\u6BEB\u79D2\u6570").default(3e3).min(1e3).max(3e4)
46
+ })).description("\u670D\u52A1\u5668\u5217\u8868\uFF0C\u6BCF\u4E2A\u670D\u52A1\u5668\u5BF9\u5E94\u4E00\u7EC4 SSH \u8FDE\u63A5\u4FE1\u606F\u548C\u547D\u4EE4\u524D\u7F00").default([]),
47
+ authority: import_koishi.Schema.number().description("\u4F7F\u7528\u547D\u4EE4\u6240\u9700\u7684\u6700\u4F4E\u6743\u9650\u7B49\u7EA7").default(4).min(1).max(5),
41
48
  debugMode: import_koishi.Schema.boolean().description("\u8C03\u8BD5\u6A21\u5F0F\uFF1A\u663E\u793A\u5B8C\u6574 SSH \u8F93\u51FA\uFF08\u542B\u654F\u611F\u5185\u5BB9\uFF0C\u4EC5\u8C03\u8BD5\u65F6\u5F00\u542F\uFF09").default(false)
42
49
  });
43
50
  var usage = `
44
- # \u65B0\u6708\u6740\u8FDC\u7A0B\u66F4\u65B0\u63D2\u4EF6
51
+ # \u65B0\u6708\u6740\u8FDC\u7A0B\u7BA1\u7406\u63D2\u4EF6
45
52
 
46
- \u901A\u8FC7 SSH \u8FDE\u63A5\u670D\u52A1\u5668\uFF0C\u81EA\u52A8\u8FDB\u5165 screen \u4F1A\u8BDD\u6267\u884C\u66F4\u65B0\u547D\u4EE4\u3002
53
+ \u901A\u8FC7 SSH \u8FDE\u63A5\u670D\u52A1\u5668\uFF0C\u81EA\u52A8\u8FDB\u5165 screen \u4F1A\u8BDD\u6267\u884C\u7BA1\u7406\u547D\u4EE4\u3002
47
54
  \u5371\u9669\u64CD\u4F5C\uFF0C\u8BF7\u52A1\u5FC5\u8BBE\u7F6E\u8DB3\u591F\u7684\u6743\u9650\u7B49\u7EA7\u3002
48
55
 
49
- ## \u4F7F\u7528\u65B9\u6CD5
56
+ ## \u914D\u7F6E\u65B9\u6CD5
50
57
 
51
- \u5728\u7FA4\u91CC\u53D1\u9001 **\u66F4\u65B0\u65B0\u6708\u6740** \u5373\u53EF\u89E6\u53D1\u66F4\u65B0\u6D41\u7A0B\u3002
58
+ \u5728\u63D2\u4EF6\u914D\u7F6E\u4E2D\u6DFB\u52A0\u670D\u52A1\u5668\u5217\u8868\uFF0C\u6BCF\u4E2A\u670D\u52A1\u5668\u914D\u7F6E\uFF1A
59
+ - **\u540D\u79F0**\uFF1A\u7528\u4F5C\u547D\u4EE4\u524D\u7F00\uFF0C\u5982\u586B\u5199"\u5B98\u670D"\uFF0C\u5219\u547D\u4EE4\u4E3A **\u5B98\u670D.u**\u3001**\u5B98\u670D.stat** \u7B49
60
+ - **SSH \u4FE1\u606F**\uFF1A\u4E3B\u673A\u3001\u7AEF\u53E3\u3001\u7528\u6237\u540D\u3001\u5BC6\u7801
61
+ - **screen \u4F1A\u8BDD**\uFF1A\u6709\u591A\u4E2A screen \u65F6\u586B\u5199\u4F1A\u8BDD\u6807\u8BC6
62
+ - **\u64CD\u4F5C\u5458\u767D\u540D\u5355**\uFF1A\u586B\u5199 QQ \u53F7\uFF08\u9017\u53F7\u5206\u9694\uFF09\uFF0C\u4E0D\u5728\u767D\u540D\u5355\u5185\u7684\u7528\u6237\u6267\u884C\u547D\u4EE4\u65F6 bot \u9759\u9ED8\u4E0D\u54CD\u5E94
52
63
 
53
- ## \u5DE5\u4F5C\u6D41\u7A0B
64
+ ## \u547D\u4EE4\u5217\u8868
54
65
 
55
- 1. SSH \u8FDE\u63A5\u5230\u670D\u52A1\u5668
56
- 2. \u6253\u5F00\u5E26 PTY \u7684\u4EA4\u4E92\u5F0F shell
57
- 3. \u53D1\u9001 \`screen -r [\u4F1A\u8BDDID]\` \u8FDB\u5165\u65B0\u6708\u6740 screen \u4F1A\u8BDD
58
- 4. \u53D1\u9001\u66F4\u65B0\u547D\u4EE4\uFF08\u9ED8\u8BA4 \`u\`\uFF09
59
- 5. \u7B49\u5F85\u66F4\u65B0\u8F93\u51FA
60
- 6. \u53D1\u9001 \`Ctrl-a d\` \u5206\u79BB screen \u4F1A\u8BDD
61
- 7. \u5173\u95ED SSH \u8FDE\u63A5\uFF0C\u8FD4\u56DE\u66F4\u65B0\u65E5\u5FD7
66
+ \u6240\u6709\u547D\u4EE4\u683C\u5F0F\uFF1A\`\u670D\u52A1\u5668\u540D.\u5B50\u547D\u4EE4\`
67
+
68
+ | \u547D\u4EE4 | \u522B\u540D | \u8BF4\u660E |
69
+ |------|------|------|
70
+ | \`\u670D\u52A1\u5668.u\` | \u2014 | \u8FDC\u7A0B\u66F4\u65B0\u670D\u52A1\u5668 |
71
+ | \`\u670D\u52A1\u5668.r\` | \u2014 | \u8FDC\u7A0B\u91CD\u542F\u670D\u52A1\u5668 |
72
+ | \`\u670D\u52A1\u5668.stat\` | \u2014 | \u67E5\u770B\u8FD0\u884C\u72B6\u6001 |
73
+ | \`\u670D\u52A1\u5668.reloadconf\` | \`.r\` (\u91CD\u8F7D) | \u91CD\u8F7D\u914D\u7F6E\u6587\u4EF6 |
74
+ | \`\u670D\u52A1\u5668.lsplayer\` | \u2014 | \u67E5\u770B\u5728\u7EBF\u73A9\u5BB6 |
75
+ | \`\u670D\u52A1\u5668.lsroom [id]\` | \u2014 | \u67E5\u770B\u623F\u95F4\u5217\u8868 |
76
+ | \`\u670D\u52A1\u5668.msg <\u5185\u5BB9>\` | \`.m\` | \u53D1\u5168\u4F53\u516C\u544A |
77
+ | \`\u670D\u52A1\u5668.msgroom <\u623F\u95F4> <\u5185\u5BB9>\` | \`.mr\` | \u5411\u623F\u95F4\u53D1\u6D88\u606F |
78
+ | \`\u670D\u52A1\u5668.kick <\u73A9\u5BB6>\` | \u2014 | \u8E22\u51FA\u73A9\u5BB6 |
79
+ | \`\u670D\u52A1\u5668.killroom <\u623F\u95F4>\` | \u2014 | \u5E9F\u5F03\u623F\u95F4 |
80
+ | \`\u670D\u52A1\u5668.checklobby\` | \u2014 | \u6E05\u5927\u5385\u50F5\u5C38 |
81
+ | \`\u670D\u52A1\u5668.ban <\u76EE\u6807>\` | \u2014 | \u5C01\u7981\u8D26\u53F7 |
82
+ | \`\u670D\u52A1\u5668.unban <\u76EE\u6807>\` | \u2014 | \u89E3\u5C01\u8D26\u53F7 |
83
+ | \`\u670D\u52A1\u5668.banip <IP>\` | \u2014 | \u5C01\u7981 IP |
84
+ | \`\u670D\u52A1\u5668.unbanip <IP>\` | \u2014 | \u89E3\u5C01 IP |
85
+ | \`\u670D\u52A1\u5668.banuuid <UUID>\` | \u2014 | \u5C01\u7981 UUID |
86
+ | \`\u670D\u52A1\u5668.unbanuuid <UUID>\` | \u2014 | \u89E3\u5C01 UUID |
87
+ | \`\u670D\u52A1\u5668.tempban <\u76EE\u6807> <\u65F6\u957F>\` | \u2014 | \u4E34\u65F6\u5C01\u7981 |
88
+ | \`\u670D\u52A1\u5668.tempmute <\u76EE\u6807> <\u65F6\u957F>\` | \u2014 | \u4E34\u65F6\u7981\u8A00 |
89
+ | \`\u670D\u52A1\u5668.unmute <\u76EE\u6807>\` | \u2014 | \u89E3\u9664\u7981\u8A00 |
90
+ | \`\u670D\u52A1\u5668.whitelist <\u64CD\u4F5C>\` | \u2014 | \u7BA1\u7406\u767D\u540D\u5355 |
91
+ | \`\u670D\u52A1\u5668.resetpassword <\u8D26\u53F7>\` | \`.rp\` | \u91CD\u7F6E\u5BC6\u7801 |
92
+ | \`\u670D\u52A1\u5668.pkgs\` | \u2014 | \u67E5\u770B\u6269\u5C55\u5305 |
93
+ | \`\u670D\u52A1\u5668.syncpkgs\` | \u2014 | \u540C\u6B65\u6269\u5C55\u5305 |
94
+ | \`\u670D\u52A1\u5668.install <URL>\` | \u2014 | \u5B89\u88C5\u6269\u5C55\u5305 |
95
+ | \`\u670D\u52A1\u5668.remove <\u540D\u79F0>\` | \u2014 | \u79FB\u9664\u6269\u5C55\u5305 |
96
+ | \`\u670D\u52A1\u5668.enable <\u540D\u79F0>\` | \u2014 | \u542F\u7528\u6269\u5C55\u5305 |
97
+ | \`\u670D\u52A1\u5668.disable <\u540D\u79F0>\` | \u2014 | \u7981\u7528\u6269\u5C55\u5305 |
62
98
 
63
99
  ## \u6CE8\u610F\u4E8B\u9879
64
100
 
65
- - screen \u4F1A\u8BDD\u5FC5\u987B\u662F **detached** \u72B6\u6001\uFF0C\u5982\u679C\u5DF2\u88AB\u4EBA attach\uFF0C\u9700\u8981\u5148\u7528 \`screen -d -r\`
101
+ - screen \u4F1A\u8BDD\u5FC5\u987B\u662F **detached** \u72B6\u6001
66
102
  - \u672C\u63D2\u4EF6\u6D89\u53CA\u670D\u52A1\u5668\u5B89\u5168\uFF0C\u8BF7\u52A1\u5FC5\u8BBE\u7F6E\u8DB3\u591F\u7684\u6743\u9650\u7B49\u7EA7
67
103
 
68
104
  ## \u53CD\u9988\u6E20\u9053
@@ -70,47 +106,289 @@ QQ \u7FA4\uFF1A1078815356
70
106
  `;
71
107
  function apply(ctx, config) {
72
108
  const logger = ctx.logger("freekill-u");
73
- ctx.command("\u66F4\u65B0\u65B0\u6708\u6740", "\u8FDC\u7A0B\u66F4\u65B0\u65B0\u6708\u6740\u670D\u52A1\u5668").userFields(["authority"]).action(async ({ session }) => {
74
- if (!config.host || !config.username) {
75
- return "\u26A0\uFE0F \u8BF7\u5148\u5728\u63D2\u4EF6\u914D\u7F6E\u4E2D\u586B\u5199 SSH \u8FDE\u63A5\u4FE1\u606F\u3002";
109
+ for (const server of config.servers) {
110
+ registerServerCommands(ctx, config, server, logger);
111
+ }
112
+ }
113
+ function registerServerCommands(ctx, config, server, logger) {
114
+ const prefix = server.name;
115
+ function checkAuth(session) {
116
+ if (!server.host || !server.username) return `\u26A0\uFE0F [${prefix}] \u8BF7\u5148\u5728\u63D2\u4EF6\u914D\u7F6E\u4E2D\u586B\u5199 SSH \u8FDE\u63A5\u4FE1\u606F\u3002`;
117
+ if (server.operators && server.operators.trim()) {
118
+ const allowedIds = server.operators.split(/[,,\s]+/).map((s) => s.trim()).filter(Boolean);
119
+ if (allowedIds.length > 0) {
120
+ const userId = session.userId || "";
121
+ if (!allowedIds.includes(userId)) return void 0;
122
+ }
76
123
  }
77
124
  const userAuthority = session.user?.authority ?? 0;
78
- if (userAuthority < config.authority) {
79
- return `\u26A0\uFE0F \u6743\u9650\u4E0D\u8DB3\uFF0C\u9700\u8981\u7B49\u7EA7 ${config.authority} \u4EE5\u4E0A\u3002`;
80
- }
125
+ if (userAuthority < config.authority) return `\u26A0\uFE0F \u6743\u9650\u4E0D\u8DB3\uFF0C\u9700\u8981\u7B49\u7EA7 ${config.authority} \u4EE5\u4E0A\u3002`;
126
+ return null;
127
+ }
128
+ async function execShellCmd(session, shellCmd, label) {
81
129
  const startTime = Date.now();
82
- await session.send("\u{1F50C} \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668\u2026");
83
130
  try {
84
- const result = await executeUpdate(config);
131
+ const result = await executeShellCommand(shellCmd, server);
85
132
  const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
86
- const lines = ["\u2705 \u65B0\u6708\u6740\u66F4\u65B0\u5B8C\u6210\uFF01", `\u23F1 \u8017\u65F6 ${elapsed} \u79D2`];
87
- if (result.hasError) {
88
- lines.push("\u26A0\uFE0F \u68C0\u6D4B\u5230\u53EF\u80FD\u7684\u9519\u8BEF\uFF0C\u5EFA\u8BAE\u68C0\u67E5\u670D\u52A1\u5668\u65E5\u5FD7\u3002");
133
+ const output = cleanShellOutput(result.output);
134
+ if (output.length > 1500) {
135
+ return `\u{1F4CB} [${prefix}] ${label}
136
+ \u23F1 ${elapsed}s
137
+
138
+ ${output.slice(-1500)}
139
+ \u2026\uFF08\u8F93\u51FA\u5DF2\u622A\u65AD\uFF09`;
89
140
  }
141
+ return `\u{1F4CB} [${prefix}] ${label}
142
+ \u23F1 ${elapsed}s
143
+
144
+ ${output || "(\u65E0\u8F93\u51FA)"}`;
145
+ } catch (e) {
146
+ const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
147
+ logger.warn("Shell\u547D\u4EE4\u5931\u8D25", { server: prefix, cmd: shellCmd, error: e?.message || String(e) });
148
+ return `\u274C [${prefix}] ${label} \u5931\u8D25\uFF08${elapsed}s\uFF09\uFF1A${e?.message || String(e)}`;
149
+ }
150
+ }
151
+ ctx.command(`${prefix}`, `${prefix} \u670D\u52A1\u5668\u7BA1\u7406`);
152
+ ctx.command(`${prefix}.u`, `\u66F4\u65B0 ${prefix} \u670D\u52A1\u5668`).userFields(["authority"]).action(async ({ session }) => {
153
+ const err = checkAuth(session);
154
+ if (err === void 0) return;
155
+ if (err) return err;
156
+ const startTime = Date.now();
157
+ await session.send(`\u{1F50C} [${prefix}] \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668\u2026`);
158
+ try {
159
+ const result = await executeUpdate(server);
160
+ const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
161
+ const lines = [`\u2705 [${prefix}] \u66F4\u65B0\u5B8C\u6210\uFF01`, `\u23F1 \u8017\u65F6 ${elapsed} \u79D2`];
162
+ if (result.hasError) lines.push("\u26A0\uFE0F \u68C0\u6D4B\u5230\u53EF\u80FD\u7684\u9519\u8BEF\uFF0C\u5EFA\u8BAE\u68C0\u67E5\u670D\u52A1\u5668\u65E5\u5FD7\u3002");
90
163
  if (config.debugMode && result.output) {
91
164
  let output = filterSensitive(result.output);
92
- if (output.length > 2e3) {
93
- output = output.slice(-2e3) + "\n\u2026\uFF08\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u4EC5\u663E\u793A\u672B\u5C3E 2000 \u5B57\u7B26\uFF09";
94
- }
165
+ if (output.length > 2e3) output = output.slice(-2e3) + "\n\u2026\uFF08\u8F93\u51FA\u5DF2\u622A\u65AD\uFF09";
95
166
  lines.push(`
96
167
  \u{1F4CB} \u66F4\u65B0\u8F93\u51FA\uFF1A
97
168
  ${output}`);
98
169
  }
99
- if (result.hasError) {
100
- logger.warn("\u66F4\u65B0\u53EF\u80FD\u5931\u8D25", { elapsed, lines: result.lineCount });
170
+ if (result.hasError) logger.warn("\u66F4\u65B0\u53EF\u80FD\u5931\u8D25", { server: prefix, elapsed, lines: result.lineCount });
171
+ await session.send(lines.join("\n"));
172
+ } catch (e) {
173
+ const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
174
+ logger.warn("\u66F4\u65B0\u5931\u8D25", { server: prefix, error: e?.message || String(e), elapsed });
175
+ await session.send(`\u274C [${prefix}] \u66F4\u65B0\u5931\u8D25\uFF08${elapsed}s\uFF09\uFF1A${e?.message || String(e)}`);
176
+ }
177
+ });
178
+ ctx.command(`${prefix}.r`, `\u91CD\u542F ${prefix} \u670D\u52A1\u5668`).userFields(["authority"]).action(async ({ session }) => {
179
+ const err = checkAuth(session);
180
+ if (err === void 0) return;
181
+ if (err) return err;
182
+ const startTime = Date.now();
183
+ await session.send(`\u{1F50C} [${prefix}] \u6B63\u5728\u8FDE\u63A5\u670D\u52A1\u5668\u2026`);
184
+ try {
185
+ const result = await executeRestart(server);
186
+ const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
187
+ const lines = [`\u2705 [${prefix}] \u91CD\u542F\u5B8C\u6210\uFF01`, `\u23F1 \u8017\u65F6 ${elapsed} \u79D2`];
188
+ if (result.hasError) lines.push("\u26A0\uFE0F \u68C0\u6D4B\u5230\u53EF\u80FD\u7684\u9519\u8BEF\uFF0C\u5EFA\u8BAE\u68C0\u67E5\u670D\u52A1\u5668\u65E5\u5FD7\u3002");
189
+ if (config.debugMode && result.output) {
190
+ let output = filterSensitive(result.output);
191
+ if (output.length > 2e3) output = output.slice(-2e3) + "\n\u2026\uFF08\u8F93\u51FA\u5DF2\u622A\u65AD\uFF09";
192
+ lines.push(`
193
+ \u{1F4CB} \u91CD\u542F\u8F93\u51FA\uFF1A
194
+ ${output}`);
101
195
  }
196
+ if (result.hasError) logger.warn("\u91CD\u542F\u53EF\u80FD\u5931\u8D25", { server: prefix, elapsed, lines: result.lineCount });
102
197
  await session.send(lines.join("\n"));
103
198
  } catch (e) {
104
199
  const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
105
- logger.warn("\u66F4\u65B0\u5931\u8D25", { error: e?.message || String(e), elapsed });
106
- await session.send(`\u274C \u66F4\u65B0\u5931\u8D25\uFF08\u8017\u65F6 ${elapsed} \u79D2\uFF09\uFF1A${e?.message || String(e)}`);
200
+ logger.warn("\u91CD\u542F\u5931\u8D25", { server: prefix, error: e?.message || String(e), elapsed });
201
+ await session.send(`\u274C [${prefix}] \u91CD\u542F\u5931\u8D25\uFF08${elapsed}s\uFF09\uFF1A${e?.message || String(e)}`);
107
202
  }
108
203
  });
204
+ ctx.command(`${prefix}.stat`, "\u67E5\u770B\u670D\u52A1\u5668\u8FD0\u884C\u72B6\u6001\uFF08GC \u7B49\uFF09").userFields(["authority"]).action(async ({ session }) => {
205
+ const err = checkAuth(session);
206
+ if (err === void 0) return;
207
+ if (err) return err;
208
+ await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
209
+ return execShellCmd(session, "stat", "stat");
210
+ });
211
+ ctx.command(`${prefix}.reloadconf`, "\u91CD\u8F7D\u670D\u52A1\u5668\u914D\u7F6E\u6587\u4EF6").userFields(["authority"]).action(async ({ session }) => {
212
+ const err = checkAuth(session);
213
+ if (err === void 0) return;
214
+ if (err) return err;
215
+ await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
216
+ return execShellCmd(session, "reloadconf", "reloadconf");
217
+ });
218
+ ctx.command(`${prefix}.lsplayer`, "\u67E5\u770B\u6240\u6709\u5728\u7EBF\u73A9\u5BB6").userFields(["authority"]).action(async ({ session }) => {
219
+ const err = checkAuth(session);
220
+ if (err === void 0) return;
221
+ if (err) return err;
222
+ await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
223
+ return execShellCmd(session, "lsplayer", "lsplayer");
224
+ });
225
+ ctx.command(`${prefix}.lsroom [id]`, "\u67E5\u770B\u8FD0\u884C\u4E2D\u7684\u623F\u95F4\uFF08\u53EF\u6307\u5B9A\u623F\u95F4ID\u67E5\u770B\u8BE6\u60C5\uFF09").userFields(["authority"]).action(async ({ session }, id) => {
226
+ const err = checkAuth(session);
227
+ if (err === void 0) return;
228
+ if (err) return err;
229
+ await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
230
+ const cmd = id ? `lsroom ${id}` : "lsroom";
231
+ return execShellCmd(session, cmd, cmd);
232
+ });
233
+ ctx.command(`${prefix}.msg <message:text>`, "\u5411\u5168\u4F53\u73A9\u5BB6\u53D1\u9001\u516C\u544A").alias(`${prefix}.m`).userFields(["authority"]).action(async ({ session }, message) => {
234
+ const err = checkAuth(session);
235
+ if (err === void 0) return;
236
+ if (err) return err;
237
+ await session.send(`\u{1F50C} [${prefix}] \u53D1\u9001\u4E2D\u2026`);
238
+ return execShellCmd(session, `msg ${message}`, "msg");
239
+ });
240
+ ctx.command(`${prefix}.msgroom <roomId> <message:text>`, "\u5411\u6307\u5B9A\u623F\u95F4\u53D1\u9001\u6D88\u606F").alias(`${prefix}.mr`).userFields(["authority"]).action(async ({ session }, roomId, message) => {
241
+ const err = checkAuth(session);
242
+ if (err === void 0) return;
243
+ if (err) return err;
244
+ await session.send(`\u{1F50C} [${prefix}] \u53D1\u9001\u4E2D\u2026`);
245
+ return execShellCmd(session, `msgroom ${roomId} ${message}`, "msgroom");
246
+ });
247
+ ctx.command(`${prefix}.kick <name:text>`, "\u8E22\u51FA\u6307\u5B9A\u73A9\u5BB6").userFields(["authority"]).action(async ({ session }, name2) => {
248
+ const err = checkAuth(session);
249
+ if (err === void 0) return;
250
+ if (err) return err;
251
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
252
+ return execShellCmd(session, `kick ${name2}`, "kick");
253
+ });
254
+ ctx.command(`${prefix}.killroom <roomId>`, "\u8E22\u51FA\u623F\u95F4\u6240\u6709\u4EBA\u5E76\u5E9F\u5F03\u623F\u95F4").userFields(["authority"]).action(async ({ session }, roomId) => {
255
+ const err = checkAuth(session);
256
+ if (err === void 0) return;
257
+ if (err) return err;
258
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
259
+ return execShellCmd(session, `killroom ${roomId}`, "killroom");
260
+ });
261
+ ctx.command(`${prefix}.checklobby`, "\u6E05\u9664\u5927\u5385\u4E2D\u7684\u50F5\u5C38\u73A9\u5BB6").userFields(["authority"]).action(async ({ session }) => {
262
+ const err = checkAuth(session);
263
+ if (err === void 0) return;
264
+ if (err) return err;
265
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
266
+ return execShellCmd(session, "checklobby", "checklobby");
267
+ });
268
+ ctx.command(`${prefix}.ban <name:text>`, "\u5C01\u7981\u6307\u5B9A\u8D26\u53F7 / IP / UUID\uFF08\u53EF\u591A\u4E2A\uFF0C\u7A7A\u683C\u5206\u9694\uFF09").userFields(["authority"]).action(async ({ session }, name2) => {
269
+ const err = checkAuth(session);
270
+ if (err === void 0) return;
271
+ if (err) return err;
272
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
273
+ return execShellCmd(session, `ban ${name2}`, "ban");
274
+ });
275
+ ctx.command(`${prefix}.unban <name:text>`, "\u89E3\u5C01\u6307\u5B9A\u8D26\u53F7\uFF08\u53EF\u591A\u4E2A\uFF09").userFields(["authority"]).action(async ({ session }, name2) => {
276
+ const err = checkAuth(session);
277
+ if (err === void 0) return;
278
+ if (err) return err;
279
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
280
+ return execShellCmd(session, `unban ${name2}`, "unban");
281
+ });
282
+ ctx.command(`${prefix}.banip <name:text>`, "\u5C01\u7981 IP \u5730\u5740").userFields(["authority"]).action(async ({ session }, name2) => {
283
+ const err = checkAuth(session);
284
+ if (err === void 0) return;
285
+ if (err) return err;
286
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
287
+ return execShellCmd(session, `banip ${name2}`, "banip");
288
+ });
289
+ ctx.command(`${prefix}.unbanip <name:text>`, "\u89E3\u5C01 IP \u5730\u5740").userFields(["authority"]).action(async ({ session }, name2) => {
290
+ const err = checkAuth(session);
291
+ if (err === void 0) return;
292
+ if (err) return err;
293
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
294
+ return execShellCmd(session, `unbanip ${name2}`, "unbanip");
295
+ });
296
+ ctx.command(`${prefix}.banuuid <name:text>`, "\u5C01\u7981 UUID").userFields(["authority"]).action(async ({ session }, name2) => {
297
+ const err = checkAuth(session);
298
+ if (err === void 0) return;
299
+ if (err) return err;
300
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
301
+ return execShellCmd(session, `banuuid ${name2}`, "banuuid");
302
+ });
303
+ ctx.command(`${prefix}.unbanuuid <name:text>`, "\u89E3\u5C01 UUID").userFields(["authority"]).action(async ({ session }, name2) => {
304
+ const err = checkAuth(session);
305
+ if (err === void 0) return;
306
+ if (err) return err;
307
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
308
+ return execShellCmd(session, `unbanuuid ${name2}`, "unbanuuid");
309
+ });
310
+ ctx.command(`${prefix}.tempban <name:text> <duration:text>`, "\u4E34\u65F6\u5C01\u7981\uFF08\u65F6\u957F\u5982 30m/2h/7d/1mo\uFF09").userFields(["authority"]).action(async ({ session }, name2, duration) => {
311
+ const err = checkAuth(session);
312
+ if (err === void 0) return;
313
+ if (err) return err;
314
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
315
+ return execShellCmd(session, `tempban ${name2} ${duration}`, "tempban");
316
+ });
317
+ ctx.command(`${prefix}.tempmute <name:text> <duration:text>`, "\u4E34\u65F6\u7981\u8A00\uFF08\u65F6\u957F\u5982 30m/2h/7d/1mo\uFF09").userFields(["authority"]).action(async ({ session }, name2, duration) => {
318
+ const err = checkAuth(session);
319
+ if (err === void 0) return;
320
+ if (err) return err;
321
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
322
+ return execShellCmd(session, `tempmute ${name2} ${duration}`, "tempmute");
323
+ });
324
+ ctx.command(`${prefix}.unmute <name:text>`, "\u89E3\u9664\u7981\u8A00\uFF08\u53EF\u591A\u4E2A\uFF09").userFields(["authority"]).action(async ({ session }, name2) => {
325
+ const err = checkAuth(session);
326
+ if (err === void 0) return;
327
+ if (err) return err;
328
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
329
+ return execShellCmd(session, `unmute ${name2}`, "unmute");
330
+ });
331
+ ctx.command(`${prefix}.whitelist <rest:text>`, "\u7BA1\u7406\u767D\u540D\u5355\uFF08add/remove \u540D\u5355\uFF09").userFields(["authority"]).action(async ({ session }, rest) => {
332
+ const err = checkAuth(session);
333
+ if (err === void 0) return;
334
+ if (err) return err;
335
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
336
+ return execShellCmd(session, `whitelist ${rest}`, "whitelist");
337
+ });
338
+ ctx.command(`${prefix}.resetpassword <name:text>`, "\u91CD\u7F6E\u8D26\u53F7\u5BC6\u7801\u4E3A 1234").alias(`${prefix}.rp`).userFields(["authority"]).action(async ({ session }, name2) => {
339
+ const err = checkAuth(session);
340
+ if (err === void 0) return;
341
+ if (err) return err;
342
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
343
+ return execShellCmd(session, `resetpassword ${name2}`, "resetpassword");
344
+ });
345
+ ctx.command(`${prefix}.install <url:text>`, "\u4ECE URL \u5B89\u88C5\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }, url) => {
346
+ const err = checkAuth(session);
347
+ if (err === void 0) return;
348
+ if (err) return err;
349
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
350
+ return execShellCmd(session, `install ${url}`, "install");
351
+ });
352
+ ctx.command(`${prefix}.remove <name:text>`, "\u79FB\u9664\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }, name2) => {
353
+ const err = checkAuth(session);
354
+ if (err === void 0) return;
355
+ if (err) return err;
356
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
357
+ return execShellCmd(session, `remove ${name2}`, "remove");
358
+ });
359
+ ctx.command(`${prefix}.pkgs`, "\u67E5\u770B\u6240\u6709\u5DF2\u5B89\u88C5\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }) => {
360
+ const err = checkAuth(session);
361
+ if (err === void 0) return;
362
+ if (err) return err;
363
+ await session.send(`\u{1F50C} [${prefix}] \u67E5\u8BE2\u4E2D\u2026`);
364
+ return execShellCmd(session, "pkgs", "pkgs");
365
+ });
366
+ ctx.command(`${prefix}.syncpkgs`, "\u4ECE\u6587\u4EF6\u7CFB\u7EDF\u540C\u6B65\u6269\u5C55\u5305\u5230\u6570\u636E\u5E93").userFields(["authority"]).action(async ({ session }) => {
367
+ const err = checkAuth(session);
368
+ if (err === void 0) return;
369
+ if (err) return err;
370
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
371
+ return execShellCmd(session, "syncpkgs", "syncpkgs");
372
+ });
373
+ ctx.command(`${prefix}.enable <name:text>`, "\u542F\u7528\u6307\u5B9A\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }, name2) => {
374
+ const err = checkAuth(session);
375
+ if (err === void 0) return;
376
+ if (err) return err;
377
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
378
+ return execShellCmd(session, `enable ${name2}`, "enable");
379
+ });
380
+ ctx.command(`${prefix}.disable <name:text>`, "\u7981\u7528\u6307\u5B9A\u6269\u5C55\u5305").userFields(["authority"]).action(async ({ session }, name2) => {
381
+ const err = checkAuth(session);
382
+ if (err === void 0) return;
383
+ if (err) return err;
384
+ await session.send(`\u{1F50C} [${prefix}] \u6267\u884C\u4E2D\u2026`);
385
+ return execShellCmd(session, `disable ${name2}`, "disable");
386
+ });
109
387
  }
110
- function executeUpdate(config) {
388
+ function executeUpdate(server) {
111
389
  return new Promise((resolve, reject) => {
112
390
  const conn = new Client();
113
- const totalTimeout = config.attachDelay + config.updateWait + 3e4;
391
+ const totalTimeout = server.attachDelay + server.updateWait + 3e4;
114
392
  const timer = setTimeout(() => {
115
393
  try {
116
394
  conn.end();
@@ -159,11 +437,11 @@ function executeUpdate(config) {
159
437
  (async () => {
160
438
  try {
161
439
  output += await collectOutput(1e3);
162
- const screenCmd = config.screenSession ? `screen -r ${config.screenSession}
440
+ const screenCmd = server.screenSession ? `screen -r ${server.screenSession}
163
441
  ` : `screen -r
164
442
  `;
165
- output += await sendAndWait(screenCmd, config.attachDelay);
166
- const updateOutput = await sendAndWait(config.updateCommand + "\n", config.updateWait);
443
+ output += await sendAndWait(screenCmd, server.attachDelay);
444
+ const updateOutput = await sendAndWait(server.updateCommand + "\n", server.updateWait);
167
445
  output += updateOutput;
168
446
  checkError(updateOutput);
169
447
  stream.write("d");
@@ -181,11 +459,215 @@ function executeUpdate(config) {
181
459
  }
182
460
  const cleanOutput = stripAnsi(output);
183
461
  const lines = cleanOutput.split("\n").filter((l) => l.trim()).length;
184
- resolve({
185
- output: cleanOutput,
186
- lineCount: lines,
187
- hasError
188
- });
462
+ resolve({ output: cleanOutput, lineCount: lines, hasError });
463
+ } catch (e) {
464
+ clearTimeout(timer);
465
+ try {
466
+ stream.close();
467
+ } catch {
468
+ }
469
+ try {
470
+ conn.end();
471
+ } catch {
472
+ }
473
+ reject(e);
474
+ }
475
+ })();
476
+ });
477
+ });
478
+ conn.on("error", (err) => {
479
+ clearTimeout(timer);
480
+ reject(new Error(`SSH \u8FDE\u63A5\u9519\u8BEF: ${err.message}`));
481
+ });
482
+ conn.connect({
483
+ host: server.host,
484
+ port: server.port,
485
+ username: server.username,
486
+ password: server.password,
487
+ readyTimeout: 15e3
488
+ });
489
+ });
490
+ }
491
+ function executeRestart(server) {
492
+ return new Promise((resolve, reject) => {
493
+ const conn = new Client();
494
+ const totalTimeout = server.attachDelay + server.quitWait + server.restartWait + 3e4;
495
+ const timer = setTimeout(() => {
496
+ try {
497
+ conn.end();
498
+ } catch {
499
+ }
500
+ reject(new Error("SSH \u64CD\u4F5C\u8D85\u65F6"));
501
+ }, totalTimeout);
502
+ conn.on("ready", () => {
503
+ conn.shell({ term: "xterm-256color", cols: 200, rows: 50 }, (err, stream) => {
504
+ if (err) {
505
+ clearTimeout(timer);
506
+ try {
507
+ conn.end();
508
+ } catch {
509
+ }
510
+ reject(new Error(`\u6253\u5F00 shell \u5931\u8D25: ${err.message}`));
511
+ return;
512
+ }
513
+ let output = "";
514
+ let hasError = false;
515
+ const collectOutput = (duration) => {
516
+ return new Promise((resolveCollected) => {
517
+ let buf = "";
518
+ const onData = (data) => {
519
+ buf += data.toString("utf8");
520
+ };
521
+ stream.on("data", onData);
522
+ setTimeout(() => {
523
+ stream.removeListener("data", onData);
524
+ resolveCollected(buf);
525
+ }, duration);
526
+ });
527
+ };
528
+ const sendAndWait = async (cmd, waitMs) => {
529
+ stream.write(cmd);
530
+ return collectOutput(waitMs);
531
+ };
532
+ const checkError = (text) => {
533
+ const lower = text.toLowerCase();
534
+ if (/error|fail|fatal|exception|拒绝|失败|错误/.test(lower)) {
535
+ if (!/0 errors?|no error/i.test(lower)) {
536
+ hasError = true;
537
+ }
538
+ }
539
+ };
540
+ (async () => {
541
+ try {
542
+ output += await collectOutput(1e3);
543
+ const screenCmd = server.screenSession ? `screen -r ${server.screenSession}
544
+ ` : `screen -r
545
+ `;
546
+ output += await sendAndWait(screenCmd, server.attachDelay);
547
+ const quitOutput = await sendAndWait("quit\n", server.quitWait);
548
+ output += quitOutput;
549
+ checkError(quitOutput);
550
+ const restartOutput = await sendAndWait("\x1B[A\n", server.restartWait);
551
+ output += restartOutput;
552
+ checkError(restartOutput);
553
+ stream.write("d");
554
+ output += await collectOutput(1e3);
555
+ stream.write("exit\n");
556
+ output += await collectOutput(500);
557
+ clearTimeout(timer);
558
+ try {
559
+ stream.close();
560
+ } catch {
561
+ }
562
+ try {
563
+ conn.end();
564
+ } catch {
565
+ }
566
+ const cleanOutput = stripAnsi(output);
567
+ const lines = cleanOutput.split("\n").filter((l) => l.trim()).length;
568
+ resolve({ output: cleanOutput, lineCount: lines, hasError });
569
+ } catch (e) {
570
+ clearTimeout(timer);
571
+ try {
572
+ stream.close();
573
+ } catch {
574
+ }
575
+ try {
576
+ conn.end();
577
+ } catch {
578
+ }
579
+ reject(e);
580
+ }
581
+ })();
582
+ });
583
+ });
584
+ conn.on("error", (err) => {
585
+ clearTimeout(timer);
586
+ reject(new Error(`SSH \u8FDE\u63A5\u9519\u8BEF: ${err.message}`));
587
+ });
588
+ conn.connect({
589
+ host: server.host,
590
+ port: server.port,
591
+ username: server.username,
592
+ password: server.password,
593
+ readyTimeout: 15e3
594
+ });
595
+ });
596
+ }
597
+ function executeShellCommand(shellCmd, server) {
598
+ return new Promise((resolve, reject) => {
599
+ const conn = new Client();
600
+ const totalTimeout = server.attachDelay + server.commandWait + 2e4;
601
+ const timer = setTimeout(() => {
602
+ try {
603
+ conn.end();
604
+ } catch {
605
+ }
606
+ reject(new Error("SSH \u64CD\u4F5C\u8D85\u65F6"));
607
+ }, totalTimeout);
608
+ conn.on("ready", () => {
609
+ conn.shell({ term: "xterm-256color", cols: 200, rows: 50 }, (err, stream) => {
610
+ if (err) {
611
+ clearTimeout(timer);
612
+ try {
613
+ conn.end();
614
+ } catch {
615
+ }
616
+ reject(new Error(`\u6253\u5F00 shell \u5931\u8D25: ${err.message}`));
617
+ return;
618
+ }
619
+ let output = "";
620
+ let hasError = false;
621
+ const collectOutput = (duration) => {
622
+ return new Promise((resolveCollected) => {
623
+ let buf = "";
624
+ const onData = (data) => {
625
+ buf += data.toString("utf8");
626
+ };
627
+ stream.on("data", onData);
628
+ setTimeout(() => {
629
+ stream.removeListener("data", onData);
630
+ resolveCollected(buf);
631
+ }, duration);
632
+ });
633
+ };
634
+ const checkError = (text) => {
635
+ const lower = text.toLowerCase();
636
+ if (/error|fail|fatal|exception|拒绝|失败|错误/.test(lower)) {
637
+ if (!/0 errors?|no error/i.test(lower)) {
638
+ hasError = true;
639
+ }
640
+ }
641
+ };
642
+ (async () => {
643
+ try {
644
+ output += await collectOutput(500);
645
+ const screenCmd = server.screenSession ? `screen -r ${server.screenSession}
646
+ ` : `screen -r
647
+ `;
648
+ output += await collectOutput(server.attachDelay);
649
+ stream.write(screenCmd);
650
+ output += await collectOutput(server.attachDelay);
651
+ stream.write(shellCmd + "\n");
652
+ const cmdOutput = await collectOutput(server.commandWait);
653
+ output += cmdOutput;
654
+ checkError(cmdOutput);
655
+ stream.write("d");
656
+ output += await collectOutput(500);
657
+ stream.write("exit\n");
658
+ output += await collectOutput(300);
659
+ clearTimeout(timer);
660
+ try {
661
+ stream.close();
662
+ } catch {
663
+ }
664
+ try {
665
+ conn.end();
666
+ } catch {
667
+ }
668
+ const cleanOutput = stripAnsi(output);
669
+ const lines = cleanOutput.split("\n").filter((l) => l.trim()).length;
670
+ resolve({ output: cleanOutput, lineCount: lines, hasError });
189
671
  } catch (e) {
190
672
  clearTimeout(timer);
191
673
  try {
@@ -206,14 +688,17 @@ function executeUpdate(config) {
206
688
  reject(new Error(`SSH \u8FDE\u63A5\u9519\u8BEF: ${err.message}`));
207
689
  });
208
690
  conn.connect({
209
- host: config.host,
210
- port: config.port,
211
- username: config.username,
212
- password: config.password,
691
+ host: server.host,
692
+ port: server.port,
693
+ username: server.username,
694
+ password: server.password,
213
695
  readyTimeout: 15e3
214
696
  });
215
697
  });
216
698
  }
699
+ function cleanShellOutput(text) {
700
+ return text.replace(/\[detached[^\n]*\n?/gi, "").replace(/\[screen[^\n]*\n?/gi, "").replace(/\n{3,}/g, "\n\n").trim();
701
+ }
217
702
  function filterSensitive(text) {
218
703
  return text.replace(/\/home\/[^/\s]+/g, "/home/***").replace(/\/root\//g, "/root/***/").replace(/(token|secret|password|passwd|key|apikey)\s*[=:]\s*\S+/gi, "$1=***").replace(/\b(\d{1,3})\.(\d{1,3})\.\d{1,3}\.\d{1,3}\b/g, "$1.$2.*.*");
219
704
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-freekill-u",
3
3
  "description": "新月杀远程更新 — 通过 SSH 连接服务器自动进入 screen 会话执行更新",
4
- "version": "1.0.1",
4
+ "version": "1.0.2",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [