terminal-bridge-setup 2.7.0 → 2.8.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/files/proxy/server.js
CHANGED
|
@@ -143,6 +143,7 @@ function maybeRunNext() {
|
|
|
143
143
|
resolve: (result) => {
|
|
144
144
|
if (pending.has(job.reqId)) {
|
|
145
145
|
clearTimeout(entry.timer);
|
|
146
|
+
if (entry.weakTimer != null) { clearTimeout(entry.weakTimer); entry.weakTimer = null; }
|
|
146
147
|
pending.delete(job.reqId);
|
|
147
148
|
try {
|
|
148
149
|
job.ws.send(JSON.stringify({ type: "result", reqId: job.reqId, ...result }));
|
|
@@ -203,7 +204,7 @@ let terminalType = "unknown"; // "unknown" | "jumpserver" | "arthas"
|
|
|
203
204
|
|
|
204
205
|
// 各类型的 prompt 正则
|
|
205
206
|
const PROMPT_RE_BY_TYPE = {
|
|
206
|
-
// JumpServer shell prompt
|
|
207
|
+
// JumpServer shell prompt(强匹配):[user@host /dir]# 或 ]$
|
|
207
208
|
// 注意:不匹配裸 >,避免输出内容里的 > 行误触发
|
|
208
209
|
jumpserver: /\]\s*[#$]\s*$/,
|
|
209
210
|
// Arthas prompt:arthas@pid>(带 arthas@ 前缀,不匹配裸 >)
|
|
@@ -212,16 +213,38 @@ const PROMPT_RE_BY_TYPE = {
|
|
|
212
213
|
unknown: /\]\s*[#$]\s*$|>\s*$/,
|
|
213
214
|
};
|
|
214
215
|
|
|
216
|
+
// 弱 prompt(无方括号的 bash 默认 PS1):user@host:~/path$ 或 root@host:~#
|
|
217
|
+
// Ubuntu/Debian 系资产的 PS1 没有方括号,强正则永远不匹配 → 全部超时。
|
|
218
|
+
// 弱匹配特征:行尾是 $ 或 #,且行内含 user@host: 或 ~/ 特征。
|
|
219
|
+
// 防误判(输出行恰好以 #/$ 结尾):不立即判定,等 WEAK_QUIET_MS 无新数据才确认。
|
|
220
|
+
const WEAK_PROMPT_LINE_RE = /[$#]$/;
|
|
221
|
+
const WEAK_PROMPT_CONTEXT_RE = /@[\w.-]+:|~\//;
|
|
222
|
+
const WEAK_QUIET_MS = 350;
|
|
223
|
+
|
|
215
224
|
// 旧名保留(cleanOutput 等处仍引用),指向宽松兜底,仅用于"删 prompt 行"的清理逻辑
|
|
216
225
|
const PROMPT_RE = PROMPT_RE_BY_TYPE.unknown;
|
|
217
226
|
|
|
227
|
+
// ANSI 清理(CSI + OSC),prompt 匹配统一在清理后的文本上做
|
|
228
|
+
function stripAnsi(s) {
|
|
229
|
+
return s
|
|
230
|
+
.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "")
|
|
231
|
+
.replace(/\x1b\][^\x07\x1b]*(\x07|\x1b\\)/g, "");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 取 ANSI 清理后文本的最后一个非空行(去尾部空白),prompt 判定用
|
|
235
|
+
function lastNonEmptyLine(s) {
|
|
236
|
+
const lines = stripAnsi(s).split("\n").map(l => l.replace(/\s+$/, ""));
|
|
237
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
238
|
+
if (lines[i].length > 0) return lines[i];
|
|
239
|
+
}
|
|
240
|
+
return "";
|
|
241
|
+
}
|
|
242
|
+
|
|
218
243
|
// 探测终端类型:扫描 ANSI 清理后的文本,按 prompt 特征判定
|
|
219
244
|
// 支持切换:如果已锁定类型 A,但检测到明确的类型 B 特征,则切换到 B
|
|
220
245
|
// (用户在 popup 切 tab 从 Arthas 切到 JumpServer 时,代理靠这条路径纠正)
|
|
221
246
|
function detectTerminalType(text) {
|
|
222
|
-
const clean = text
|
|
223
|
-
.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "")
|
|
224
|
-
.replace(/\x1b\][^\x07\x1b]*(\x07|\x1b\\)/g, "");
|
|
247
|
+
const clean = stripAnsi(text);
|
|
225
248
|
|
|
226
249
|
// Arthas prompt 特征:arthas@<pid>> (出现在任意行尾)
|
|
227
250
|
if (/arthas@\S+>\s*$/m.test(clean)) {
|
|
@@ -232,7 +255,7 @@ function detectTerminalType(text) {
|
|
|
232
255
|
return;
|
|
233
256
|
}
|
|
234
257
|
|
|
235
|
-
// JumpServer shell prompt
|
|
258
|
+
// JumpServer shell prompt 特征(红帽系):[user@host /dir]# 或 ]$
|
|
236
259
|
if (/\[[^\]\n]+@[^\]\n]+\][^\n]*[#$]\s*$/m.test(clean)) {
|
|
237
260
|
if (terminalType !== "jumpserver") {
|
|
238
261
|
terminalType = "jumpserver";
|
|
@@ -240,6 +263,16 @@ function detectTerminalType(text) {
|
|
|
240
263
|
}
|
|
241
264
|
return;
|
|
242
265
|
}
|
|
266
|
+
|
|
267
|
+
// JumpServer shell prompt 特征(Ubuntu/Debian 默认 PS1,无方括号):
|
|
268
|
+
// user@host:~/path$ 或 root@host:~#
|
|
269
|
+
if (/[\w.-]+@[\w.-]+:\S*[$#]\s*$/m.test(clean)) {
|
|
270
|
+
if (terminalType !== "jumpserver") {
|
|
271
|
+
terminalType = "jumpserver";
|
|
272
|
+
console.log(TAG, "[probe] 终端类型切换 → jumpserver(检测到 user@host:path$ prompt,无方括号)");
|
|
273
|
+
}
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
243
276
|
// 未命中任一特征,保持当前类型不变
|
|
244
277
|
}
|
|
245
278
|
|
|
@@ -350,6 +383,37 @@ function handleWsRecv(payload) {
|
|
|
350
383
|
elapsedMs: Date.now() - entry.sentAt
|
|
351
384
|
});
|
|
352
385
|
}
|
|
386
|
+
} else if (entry.phase === 0 && (terminalType === "jumpserver" || terminalType === "unknown")) {
|
|
387
|
+
// ====== 弱 prompt 兜底(Ubuntu/Debian 默认 PS1 无方括号)======
|
|
388
|
+
// 强正则要求 ] 前缀;user@host:~/path$ 这种 prompt 永远匹配不上 → 全部超时。
|
|
389
|
+
// 弱匹配:最后一个非空行以 $/# 结尾且行内含 @ 或 : 特征。
|
|
390
|
+
// 防误判:不立即判定,等 WEAK_QUIET_MS 无新数据再确认
|
|
391
|
+
// (输出行恰好以 #/$ 结尾时,后续输出到达会取消定时器)。
|
|
392
|
+
const lastLine = lastNonEmptyLine(entry.buffer);
|
|
393
|
+
const weakHit = WEAK_PROMPT_LINE_RE.test(lastLine) && WEAK_PROMPT_CONTEXT_RE.test(lastLine);
|
|
394
|
+
if (weakHit) {
|
|
395
|
+
if (entry.weakTimer == null) {
|
|
396
|
+
const snapLen = entry.buffer.length;
|
|
397
|
+
entry.weakTimer = setTimeout(() => {
|
|
398
|
+
entry.weakTimer = null;
|
|
399
|
+
if (!pending.has(reqId) || entry.buffer.length !== snapLen) return;
|
|
400
|
+
const lineNow = lastNonEmptyLine(entry.buffer);
|
|
401
|
+
if (WEAK_PROMPT_LINE_RE.test(lineNow) && WEAK_PROMPT_CONTEXT_RE.test(lineNow)) {
|
|
402
|
+
console.log(TAG, `[${reqId}] 弱 prompt 确认完成(${WEAK_QUIET_MS}ms 静默): ${lineNow.slice(-60)}`);
|
|
403
|
+
entry.lastScanLen = entry.buffer.length;
|
|
404
|
+
entry.resolve({
|
|
405
|
+
ok: true,
|
|
406
|
+
output: cleanOutput(entry.buffer, entry.cmd),
|
|
407
|
+
elapsedMs: Date.now() - entry.sentAt
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}, WEAK_QUIET_MS);
|
|
411
|
+
}
|
|
412
|
+
} else if (entry.weakTimer != null) {
|
|
413
|
+
// 新数据不再是弱 prompt 形态,取消待确认的判定
|
|
414
|
+
clearTimeout(entry.weakTimer);
|
|
415
|
+
entry.weakTimer = null;
|
|
416
|
+
}
|
|
353
417
|
}
|
|
354
418
|
}
|
|
355
419
|
}
|
|
@@ -398,11 +462,14 @@ function cleanOutput(text, cmd) {
|
|
|
398
462
|
.replace(/\r\n?/g, "\n");
|
|
399
463
|
|
|
400
464
|
// 删除 prompt 行:
|
|
401
|
-
// - shell
|
|
465
|
+
// - shell 风格(红帽系):行里出现 [user@host /cwd]# 或 ]$ → 整行删
|
|
402
466
|
// (删 "[root@host ~]# echo hello" 这种命令回显行,含粘在前面的碎片)
|
|
467
|
+
// - shell 风格(Ubuntu/Debian,无方括号):user@host:~/path$ 结尾的行
|
|
403
468
|
// - Arthas 风格:行尾是 arthas@xxx> 或单独的 > → 整行删
|
|
404
469
|
out = out.split("\n").filter(line => {
|
|
405
470
|
if (/\[[^\]\n]+@[^\]\n]+\][^\n]*[#$]/.test(line)) return false;
|
|
471
|
+
// Ubuntu prompt 行(含粘在命令回显前的情况)
|
|
472
|
+
if (/[\w.-]+@[\w.-]+:\S*[$#]\s*$/.test(line)) return false;
|
|
406
473
|
// Arthas / 通用 REPL prompt:行尾 > (允许前面有 arthas@xxx 等前缀)
|
|
407
474
|
if (/>\s*$/.test(line) && line.trim().length <= 60) return false;
|
|
408
475
|
return true;
|
package/files/skill/SKILL.md
CHANGED
|
@@ -78,8 +78,8 @@ Arthas 的能力不止于读,以下命令/用法一律禁止通过桥接执行
|
|
|
78
78
|
| 页面形态 | koko connect **iframe**(嵌在 luna 父页里) | **顶层文档**(无 iframe) |
|
|
79
79
|
| WebSocket URL | `wss://.../koko/ws/...` | `wss://.../ws?method=connectArthas...` |
|
|
80
80
|
| WS 帧格式 | **二进制帧 opcode=2**,payload 是 base64,解码后是 SSH PTY 明文 | **文本帧 opcode=1**,payload 直接是明文 ANSI |
|
|
81
|
-
| prompt 样式 |
|
|
82
|
-
| prompt
|
|
81
|
+
| prompt 样式 | 红帽系 `[root@host /dir]#`;Ubuntu 资产 `user@host:~/path$`(无方括号) | Arthas 风格 `arthas@pid>` 或 `[arthas@...]` |
|
|
82
|
+
| prompt 锚点 | 强匹配 `]\s*[#$]\s*$`;无方括号 prompt 走弱兜底(行尾 `$`/`#` + `user@host:` 特征,350ms 静默确认) | `arthas@\S+>\s*$` |
|
|
83
83
|
| sudo 检测 | 需要(cat/df 等可能被 alias 成 sudo) | 不适用(Java 诊断工具无 sudo 概念) |
|
|
84
84
|
|
|
85
85
|
**桥接层已自动处理这些差异**:content script 按是否有 `.xterm` 元素识别终端 frame(不依赖 URL),proxy 按 opcode 自动决定是否 base64 解码,prompt 锚点同时匹配两种风格。Agent 侧调用方式完全一致——都是发 `run` 帧、收 `result` 帧。
|
|
@@ -129,8 +129,11 @@ const PROMPT_RE = /\]\s*[#$]\s*$|>\s*$/;
|
|
|
129
129
|
|
|
130
130
|
| 终端 | prompt 样式 | 匹配部分 |
|
|
131
131
|
|------|------------|---------|
|
|
132
|
-
| JumpServer (shell) | `[root@host /path]#` 或 `]$` | `]\s*[#$]\s
|
|
133
|
-
|
|
|
132
|
+
| JumpServer (shell, 红帽系) | `[root@host /path]#` 或 `]$` | 强匹配 `]\s*[#$]\s*$`(命中即完成) |
|
|
133
|
+
| JumpServer (shell, Ubuntu/Debian) | `user@host:~/path$`(无方括号) | 弱匹配兜底:行尾 `$`/`#` + `user@host:`/`~/` 特征,需 350ms 静默确认 |
|
|
134
|
+
| Arthas | `arthas@pid>` 或 `[arthas@...]` | `arthas@\S+>\s*$` |
|
|
135
|
+
|
|
136
|
+
说明:Ubuntu/Debian 默认 PS1 没有方括号,强正则永远不命中会导致所有命令超时(曾出现在 Windows 同事的 Ubuntu 资产上)。弱兜底以 350ms 无新数据为确认条件,避免输出行恰好以 `#`/`$` 结尾时误判提前完成。
|
|
134
137
|
|
|
135
138
|
注意:单独的 `>` 较宽(命令输出里 `>` 偶尔出现),但配合"行尾 + ANSI 清理后 + 注入命令后才出现"三个条件,误判率可接受。
|
|
136
139
|
|
package/package.json
CHANGED