@xiaoqiong0v0/opencode-ssh-tool 0.2.6 → 0.3.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/README.md +28 -18
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/i18n.d.ts +60 -30
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +60 -30
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +164 -59
- package/dist/index.js.map +1 -1
- package/dist/local-session.d.ts +117 -0
- package/dist/local-session.d.ts.map +1 -0
- package/dist/local-session.js +365 -0
- package/dist/local-session.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +138 -39
- package/dist/server.js.map +1 -1
- package/dist/session-store.d.ts +4 -0
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js.map +1 -1
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +13 -1
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -21,14 +21,14 @@ export function startServer(port, getSessions, dir) {
|
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
if (path === "/api/status") {
|
|
24
|
-
// 跨进程聚合:所有 opencode
|
|
24
|
+
// 跨进程聚合:所有 opencode 进程写入的状态文件(含本进程,SSH + 本地/容器)
|
|
25
25
|
const states = listAllSessions(dir);
|
|
26
26
|
// 按 sessionID 分组(一个会话下多个终端)
|
|
27
27
|
const bySession = new Map();
|
|
28
28
|
for (const s of states) {
|
|
29
29
|
if (!bySession.has(s.sessionID))
|
|
30
30
|
bySession.set(s.sessionID, { title: s.title, directory: s.directory, terminals: [] });
|
|
31
|
-
bySession.get(s.sessionID).terminals.push({ name: s.name, host: s.host, user: s.user, port: s.port, connected: s.connected, busy: s.busy, pending: s.pending });
|
|
31
|
+
bySession.get(s.sessionID).terminals.push({ name: s.name, kind: s.kind, host: s.host, user: s.user, port: s.port, program: s.program, connected: s.connected, busy: s.busy, pending: s.pending });
|
|
32
32
|
}
|
|
33
33
|
const sessions = [...bySession.entries()].map(([sessionID, v]) => ({
|
|
34
34
|
sessionID,
|
|
@@ -44,32 +44,32 @@ export function startServer(port, getSessions, dir) {
|
|
|
44
44
|
const sid = url.searchParams.get("session") ?? "";
|
|
45
45
|
const name = url.searchParams.get("name") ?? "default";
|
|
46
46
|
const entry = getSessions().find((e) => e.sessionID === sid && e.name === name);
|
|
47
|
+
let pairs;
|
|
47
48
|
if (!entry) {
|
|
48
49
|
// 本进程无此会话句柄(其他进程的会话/复用服务)→ 从历史文件读取
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
// 本地/容器会话的历史目录带 local- 前缀,需按状态里的 kind 探测
|
|
51
|
+
const state = listAllSessions(dir).find((s) => s.sessionID === sid && s.name === name);
|
|
52
|
+
const histName = state?.kind === "local" ? `local-${name}` : name;
|
|
53
|
+
pairs = readHistoryFromFile(dir, sid, histName) ?? [];
|
|
54
|
+
if (pairs.length === 0) {
|
|
51
55
|
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
52
56
|
res.end("Session not found or disconnected");
|
|
53
57
|
return;
|
|
54
58
|
}
|
|
55
|
-
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
|
|
56
|
-
res.end(text);
|
|
57
|
-
return;
|
|
58
59
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
lines.push(`[ 运行中 ] ${running}`);
|
|
60
|
+
else {
|
|
61
|
+
// 命令+输出消息对(保留 ANSI 颜色,前端解析着色);运行中附加实时进度
|
|
62
|
+
pairs = [];
|
|
63
|
+
for (const pair of entry.session.getHistory().getPairs()) {
|
|
64
|
+
pairs.push({ type: "cmd", ts: pair.ts, text: pair.command });
|
|
65
|
+
pairs.push({ type: "out", text: entry.session.getHistory().readOutput(pair) });
|
|
66
|
+
}
|
|
67
|
+
const running = entry.session.getRunningOutput();
|
|
68
|
+
if (running)
|
|
69
|
+
pairs.push({ type: "run", text: running });
|
|
70
70
|
}
|
|
71
|
-
res.writeHead(200, { "Content-Type": "
|
|
72
|
-
res.end(
|
|
71
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
72
|
+
res.end(JSON.stringify({ pairs }));
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
75
|
if (path === "/") {
|
|
@@ -99,8 +99,8 @@ export function startServer(port, getSessions, dir) {
|
|
|
99
99
|
* 从历史文件读取某终端记录(跨进程场景:本进程无该会话句柄时用)
|
|
100
100
|
* @param dir 插件缓存根目录
|
|
101
101
|
* @param sessionID opencode 会话 ID
|
|
102
|
-
* @param name
|
|
103
|
-
* @returns
|
|
102
|
+
* @param name 终端名(已含 local- 前缀则按本地目录)
|
|
103
|
+
* @returns 结构化消息对(保留 ANSI);目录不存在返回 null
|
|
104
104
|
*/
|
|
105
105
|
function readHistoryFromFile(dir, sessionID, name) {
|
|
106
106
|
const hdir = join(dir, sessionID, name);
|
|
@@ -112,20 +112,20 @@ function readHistoryFromFile(dir, sessionID, name) {
|
|
|
112
112
|
return null;
|
|
113
113
|
}
|
|
114
114
|
files.sort();
|
|
115
|
-
const
|
|
115
|
+
const out = [];
|
|
116
116
|
for (const f of files) {
|
|
117
117
|
try {
|
|
118
118
|
const data = JSON.parse(readFileSync(join(hdir, f), "utf8"));
|
|
119
119
|
if (typeof data.command === "string")
|
|
120
|
-
|
|
120
|
+
out.push({ type: "cmd", ts: data.ts ?? Date.now(), text: data.command });
|
|
121
121
|
if (typeof data.output === "string")
|
|
122
|
-
|
|
122
|
+
out.push({ type: "out", text: data.output });
|
|
123
123
|
}
|
|
124
124
|
catch {
|
|
125
125
|
/* 跳过损坏文件 */
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
-
return
|
|
128
|
+
return out;
|
|
129
129
|
}
|
|
130
130
|
/** 渲染终端记录页面(黑底绿字等宽,JS 轮询自动刷新) */
|
|
131
131
|
function renderPage() {
|
|
@@ -139,24 +139,53 @@ function renderPage() {
|
|
|
139
139
|
header { position: sticky; top: 0; display: flex; align-items: center; gap: 12px; padding: 10px 16px; background: #161b22; border-bottom: 1px solid #30363d; }
|
|
140
140
|
header h1 { margin: 0; font-size: 14px; color: #e6edf3; font-weight: 600; }
|
|
141
141
|
select { background: #21262d; color: #c9d1d9; border: 1px solid #30363d; padding: 4px 8px; border-radius: 6px; }
|
|
142
|
-
pre { margin: 0; padding: 16px; font-family: "Cascadia Code", Consolas, "Courier New", monospace; font-size: 13px; line-height: 1.5; white-space: pre; overflow: auto; height: calc(100% - 52px); box-sizing: border-box; color: #c9d1d9; }
|
|
142
|
+
pre { margin: 0; padding: 16px; font-family: "Cascadia Code", Consolas, "Courier New", monospace; font-size: 13px; line-height: 1.5; white-space: pre-wrap; overflow: auto; height: calc(100% - 52px); box-sizing: border-box; color: #c9d1d9; }
|
|
143
|
+
/* 两列布局:左侧时间列(开关控制显隐),右侧内容列(命令/输出格式不变) */
|
|
144
|
+
.row { display: flex; align-items: stretch; }
|
|
145
|
+
.row .t { box-sizing: border-box; flex: 0 0 172px; color: #8b949e; padding: 0 10px 0 6px; border-right: 1px solid #30363d; white-space: pre; }
|
|
146
|
+
.row .c { flex: 1; padding-left: 12px; white-space: pre; }
|
|
147
|
+
body:not(.show-time) .row .t { display: none; }
|
|
148
|
+
/* 命令行:明显区分(背景条 + 左侧蓝条 + 加粗);用 box-shadow 不占布局,保证时间列/分割线与输出行完全对齐 */
|
|
149
|
+
.row.cmdline { background: #161b22; box-shadow: inset 3px 0 0 #58a6ff; font-weight: 600; }
|
|
150
|
+
.tgl { font-size: 12px; color: #8b949e; display: flex; align-items: center; gap: 4px; white-space: nowrap; }
|
|
143
151
|
#meta { font-size: 12px; color: #8b949e; }
|
|
152
|
+
/* 深色细滚动条:匹配暗色主题 */
|
|
153
|
+
::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
154
|
+
::-webkit-scrollbar-track { background: #161b22; }
|
|
155
|
+
::-webkit-scrollbar-thumb { background: #30363d; border-radius: 5px; border: 2px solid #161b22; }
|
|
156
|
+
::-webkit-scrollbar-thumb:hover { background: #484f58; }
|
|
157
|
+
::-webkit-scrollbar-corner { background: #161b22; }
|
|
158
|
+
* { scrollbar-width: thin; scrollbar-color: #30363d #161b22; }
|
|
159
|
+
/* 回到底部悬浮按钮:离开底部且有新消息时显示 */
|
|
160
|
+
.to-bottom-btn {
|
|
161
|
+
position: fixed; right: 24px; bottom: 24px; display: none;
|
|
162
|
+
background: #238636; color: #fff; border: none; border-radius: 20px;
|
|
163
|
+
padding: 8px 16px; font-size: 13px; cursor: pointer; z-index: 10;
|
|
164
|
+
box-shadow: 0 4px 12px rgba(0,0,0,.4);
|
|
165
|
+
}
|
|
166
|
+
.to-bottom-btn:hover { background: #2ea043; }
|
|
144
167
|
</style>
|
|
145
168
|
</head>
|
|
146
169
|
<body>
|
|
147
170
|
<header>
|
|
148
|
-
<h1
|
|
149
|
-
<select id="session" onchange="onSessionChange()"></select>
|
|
150
|
-
<select id="terminal" onchange="
|
|
171
|
+
<h1>终端记录</h1>
|
|
172
|
+
<select id="session" onchange="onSessionChange(true)"></select>
|
|
173
|
+
<select id="terminal" onchange="onSessionChange(true)"></select>
|
|
174
|
+
<label class="tgl"><input type="checkbox" id="showTime" onchange="onShowTimeChange()"> 时间</label>
|
|
151
175
|
<span id="meta"></span>
|
|
152
176
|
</header>
|
|
153
177
|
<pre id="term">加载中...</pre>
|
|
178
|
+
<button id="toBottom" class="to-bottom-btn" onclick="scrollToNewest()">↓ 新消息</button>
|
|
154
179
|
<script>
|
|
155
180
|
let sessionsData = [];
|
|
156
181
|
// 是否贴底(用户向上滚动查看历史时不自动下滚,仅贴底时跟随新输出)
|
|
157
182
|
let stickToBottom = true;
|
|
158
183
|
// 上次会话列表指纹(无变化则不重建下拉框,避免打断用户选择/焦点)
|
|
159
184
|
let lastSessionsKey = "";
|
|
185
|
+
// 上次渲染的 transcript 文本(判断是否真有新消息才显示悬浮按钮)
|
|
186
|
+
let lastTranscript = "";
|
|
187
|
+
// 新消息顶部位置(点击悬浮按钮时滚动到此处,而非底部)
|
|
188
|
+
let pendingTop = 0;
|
|
160
189
|
|
|
161
190
|
// ANSI → 彩色 HTML:消费所有 CSI 序列(颜色/光标/清屏等),SGR 着色、其余丢弃;先 HTML 转义防 XSS
|
|
162
191
|
const ANSI_BASE = ["#010101","#de382b","#39b54a","#ffc005","#006fb8","#762671","#2cb3e9","#c9d1d9"];
|
|
@@ -230,10 +259,12 @@ function renderPage() {
|
|
|
230
259
|
}
|
|
231
260
|
if (prev && [...sel.options].some(o => o.value === prev)) sel.value = prev;
|
|
232
261
|
else sel.selectedIndex = sessionsData.length ? 0 : -1;
|
|
233
|
-
onSessionChange();
|
|
262
|
+
onSessionChange(false);
|
|
234
263
|
}
|
|
235
264
|
|
|
236
|
-
function onSessionChange() {
|
|
265
|
+
function onSessionChange(forceStick) {
|
|
266
|
+
lastTranscript = "";
|
|
267
|
+
pendingTop = 0;
|
|
237
268
|
const sel = document.getElementById("session");
|
|
238
269
|
const sid = sel.value;
|
|
239
270
|
const tsel = document.getElementById("terminal");
|
|
@@ -243,13 +274,13 @@ function renderPage() {
|
|
|
243
274
|
for (const t of (s ? s.terminals : [])) {
|
|
244
275
|
const opt = document.createElement("option");
|
|
245
276
|
opt.value = t.name || "default";
|
|
246
|
-
opt.textContent = (t.name || "default") + " " + (t.connected ? "●" : "○") + (t.busy ? " ⏳" : "");
|
|
277
|
+
opt.textContent = (t.name || "default") + (t.kind === "local" ? " [本地]" : "") + " " + (t.connected ? "●" : "○") + (t.busy ? " ⏳" : "");
|
|
247
278
|
tsel.appendChild(opt);
|
|
248
279
|
}
|
|
249
280
|
if (prev && [...tsel.options].some(o => o.value === prev)) tsel.value = prev;
|
|
250
281
|
else tsel.selectedIndex = tsel.options.length ? 0 : -1;
|
|
251
|
-
//
|
|
252
|
-
stickToBottom = true;
|
|
282
|
+
// 仅用户主动切换会话/终端时强制回到底部;自动轮询重建不打扰当前滚动位置
|
|
283
|
+
if (forceStick) stickToBottom = true;
|
|
253
284
|
loadTranscript();
|
|
254
285
|
}
|
|
255
286
|
|
|
@@ -262,11 +293,79 @@ function renderPage() {
|
|
|
262
293
|
if (!sid || !name) { pre.textContent = "无会话,请先 ssh_connect"; return; }
|
|
263
294
|
// 更新前判断是否贴底:用户已向上滚动离开底部则不自动下滚,保持当前位置
|
|
264
295
|
if (pre.scrollTop + pre.clientHeight >= pre.scrollHeight - 30) stickToBottom = true;
|
|
296
|
+
const showTime = document.getElementById("showTime").checked;
|
|
297
|
+
document.body.classList.toggle("show-time", showTime);
|
|
265
298
|
const r = await fetch("/api/transcript?session=" + encodeURIComponent(sid) + "&name=" + encodeURIComponent(name));
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
299
|
+
const data = await r.json();
|
|
300
|
+
const pairs = data.pairs || [];
|
|
301
|
+
// 渲染前旧内容完整高度 = 新消息顶部位置(旧内容不变时高度稳定)
|
|
302
|
+
const prevHeight = pre.scrollHeight;
|
|
303
|
+
// 内容是否有新变化(有新消息才显示悬浮按钮)
|
|
304
|
+
const sig = JSON.stringify(pairs);
|
|
305
|
+
const changed = sig !== lastTranscript;
|
|
306
|
+
lastTranscript = sig;
|
|
307
|
+
pre.innerHTML = pairs.map((p) => {
|
|
308
|
+
if (p.type === "cmd") {
|
|
309
|
+
const t = showTime ? fmtTime(p.ts) : "";
|
|
310
|
+
return '<div class="row cmdline"><span class="t">' + t + '</span><span class="c">' + ansiToHtml(p.text) + '</span></div>';
|
|
311
|
+
}
|
|
312
|
+
// out / run:输出列,保留 ANSI 彩色,时间列留空(不改变输出格式)
|
|
313
|
+
const label = p.type === "run" ? "[运行中] " : "";
|
|
314
|
+
return '<div class="row"><span class="t"></span><span class="c">' + label + ansiToHtml(p.text) + '</span></div>';
|
|
315
|
+
}).join("");
|
|
316
|
+
const cmdCount = pairs.filter((p) => p.type === "cmd").length;
|
|
317
|
+
document.getElementById("meta").textContent = sid + "/" + name + " · " + cmdCount + " 条命令 · 每 2s 自动刷新";
|
|
318
|
+
if (stickToBottom) {
|
|
319
|
+
pre.scrollTop = pre.scrollHeight;
|
|
320
|
+
toBottomBtn.style.display = "none";
|
|
321
|
+
} else if (pendingTop > 0) {
|
|
322
|
+
// 离开底部且有未读新消息 → 显示悬浮按钮(pendingTop 为跳转位置)
|
|
323
|
+
toBottomBtn.style.display = "block";
|
|
324
|
+
}
|
|
325
|
+
// 无论贴底与否,有内容变化都记录新消息顶部(供用户滚上去后跳转)
|
|
326
|
+
if (changed && pre.scrollHeight > pre.clientHeight) {
|
|
327
|
+
pendingTop = prevHeight;
|
|
328
|
+
if (stickToBottom) {
|
|
329
|
+
// 贴底跟随 = 已读到最新,清除未读标记(用户滚上去才重新提示)
|
|
330
|
+
pendingTop = 0;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// 时间戳格式化 yyyy-MM-dd HH:mm:ss
|
|
336
|
+
function fmtTime(ts) {
|
|
337
|
+
const d = new Date(ts);
|
|
338
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
339
|
+
return d.getFullYear() + "-" + p(d.getMonth() + 1) + "-" + p(d.getDate()) + " " + p(d.getHours()) + ":" + p(d.getMinutes()) + ":" + p(d.getSeconds());
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// 时间开关:localStorage 持久化,刷新页面保持状态
|
|
343
|
+
function onShowTimeChange() {
|
|
344
|
+
const el = document.getElementById("showTime");
|
|
345
|
+
localStorage.setItem("showTime", el.checked ? "1" : "0");
|
|
346
|
+
document.body.classList.toggle("show-time", el.checked);
|
|
347
|
+
loadTranscript();
|
|
348
|
+
}
|
|
349
|
+
document.getElementById("showTime").checked = localStorage.getItem("showTime") === "1";
|
|
350
|
+
document.body.classList.toggle("show-time", document.getElementById("showTime").checked);
|
|
351
|
+
|
|
352
|
+
// 用户滚动:贴底 → 恢复跟随并隐藏按钮;离开底部 → 取消自动贴底
|
|
353
|
+
const termPre = document.getElementById("term");
|
|
354
|
+
const toBottomBtn = document.getElementById("toBottom");
|
|
355
|
+
termPre.addEventListener("scroll", () => {
|
|
356
|
+
if (termPre.scrollTop + termPre.clientHeight >= termPre.scrollHeight - 30) {
|
|
357
|
+
stickToBottom = true;
|
|
358
|
+
toBottomBtn.style.display = "none";
|
|
359
|
+
pendingTop = 0; // 贴底 = 已读到最新,清除未读标记
|
|
360
|
+
} else {
|
|
361
|
+
stickToBottom = false;
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
// 点击悬浮按钮:滚动到新消息顶部(阅读未读内容),不强制回到底部
|
|
365
|
+
function scrollToNewest() {
|
|
366
|
+
termPre.scrollTop = pendingTop > 0 ? pendingTop : termPre.scrollHeight;
|
|
367
|
+
pendingTop = 0;
|
|
368
|
+
toBottomBtn.style.display = "none";
|
|
270
369
|
}
|
|
271
370
|
|
|
272
371
|
loadSessions();
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAE9C,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAmBpD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,WAAiC,EAAE,GAAW;IACtF,IAAI,UAAU,GAAG,IAAI,CAAA;IACrB,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAA;QACvD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAA;QAEzB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAA;YAC1D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YACrC,OAAM;QACR,CAAC;QAED,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3B,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/session-store.d.ts
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
export interface SessionState {
|
|
3
3
|
sessionID: string;
|
|
4
4
|
name: string;
|
|
5
|
+
/** 会话类型:ssh 远程 / local 本地·容器 */
|
|
6
|
+
kind?: "ssh" | "local";
|
|
5
7
|
host?: string;
|
|
6
8
|
user?: string;
|
|
7
9
|
port?: number;
|
|
10
|
+
/** 本地/容器会话的程序(如 pwsh、docker exec ...) */
|
|
11
|
+
program?: string;
|
|
8
12
|
connected: boolean;
|
|
9
13
|
busy: boolean;
|
|
10
14
|
pending: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAKA,yBAAyB;AACzB,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAUD,8BAA8B;AAC9B,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAQ9E;AAED,4BAA4B;AAC5B,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM3F;AAED,oCAAoC;AACpC,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAoBjE"}
|
|
1
|
+
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAKA,yBAAyB;AACzB,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,gCAAgC;IAChC,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,CAAA;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAUD,8BAA8B;AAC9B,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI,CAQ9E;AAED,4BAA4B;AAC5B,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM3F;AAED,oCAAoC;AACpC,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,CAoBjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAE5C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACrF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"session-store.js","sourceRoot":"","sources":["../src/session-store.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAE5C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACrF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAuBhC,uBAAuB;AACvB,MAAM,YAAY,GAAG,UAAU,CAAA;AAE/B,wDAAwD;AACxD,SAAS,SAAS,CAAC,WAAmB,EAAE,SAAiB,EAAE,IAAY;IACrE,OAAO,IAAI,CAAC,WAAW,EAAE,GAAG,SAAS,IAAI,IAAI,OAAO,CAAC,CAAA;AACvD,CAAC;AAED,8BAA8B;AAC9B,MAAM,UAAU,iBAAiB,CAAC,SAAiB,EAAE,KAAmB;IACtE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;QACzC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACnC,aAAa,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAA;IAC3F,CAAC;IAAC,MAAM,CAAC;QACP,WAAW;IACb,CAAC;AACH,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,SAAiB,EAAE,IAAY;IACnF,IAAI,CAAC;QACH,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACpF,CAAC;IAAC,MAAM,CAAC;QACP,QAAQ;IACV,CAAC;AACH,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;IACzC,IAAI,KAAe,CAAA;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;IACD,MAAM,GAAG,GAAmB,EAAE,CAAA;IAC9B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAiB,CAAA;YACxE,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;IACH,CAAC;IACD,gBAAgB;IAChB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,CAAA;IAC/D,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export declare function genSentinel(): string;
|
|
6
6
|
/**
|
|
7
7
|
* 剔除 PTY 回显的命令行(含提示符前缀,如 "user@host:~$ cmd"),并清理残留 CR
|
|
8
|
+
* 同时剔除含哨兵标记的行(上次命令在哨兵之后到达的回显残留,避免污染下一条输出)
|
|
8
9
|
* @param raw 原始输出
|
|
9
10
|
* @param cmd 已发送命令(组合串)
|
|
10
11
|
* @returns 剔除回显后的输出
|
|
@@ -30,4 +31,10 @@ export declare function collapseCarriage(s: string): string;
|
|
|
30
31
|
* @returns 剥离尾部提示符后的文本
|
|
31
32
|
*/
|
|
32
33
|
export declare function stripPrompt(s: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* 时间戳格式化为 yyyy-MM-dd HH:mm:ss
|
|
36
|
+
* @param ts 毫秒时间戳
|
|
37
|
+
* @returns 格式化时间
|
|
38
|
+
*/
|
|
39
|
+
export declare function fmtTime(ts: number): string;
|
|
33
40
|
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG3C;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAYlD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAI1C"}
|
package/dist/utils.js
CHANGED
|
@@ -9,13 +9,15 @@ export function genSentinel() {
|
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* 剔除 PTY 回显的命令行(含提示符前缀,如 "user@host:~$ cmd"),并清理残留 CR
|
|
12
|
+
* 同时剔除含哨兵标记的行(上次命令在哨兵之后到达的回显残留,避免污染下一条输出)
|
|
12
13
|
* @param raw 原始输出
|
|
13
14
|
* @param cmd 已发送命令(组合串)
|
|
14
15
|
* @returns 剔除回显后的输出
|
|
15
16
|
*/
|
|
16
17
|
export function stripEcho(raw, cmd) {
|
|
18
|
+
const SENTINEL_LINE = /__SSH_DONE_[0-9a-f]+__/;
|
|
17
19
|
const lines = raw.split(/\r?\n/).map((line) => line.replace(/\r/g, "").trimEnd());
|
|
18
|
-
return lines.filter((line) => line !== "" && !line.includes(cmd)).join("\n");
|
|
20
|
+
return lines.filter((line) => line !== "" && !line.includes(cmd) && !SENTINEL_LINE.test(line)).join("\n");
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* 剥离 ANSI 转义序列(颜色、光标控制等)
|
|
@@ -57,4 +59,14 @@ export function stripPrompt(s) {
|
|
|
57
59
|
.replace(/(?:^|[\r\n])\s*(?:[\w.-]+@)?[\w.-]+:[^\r\n]*[$#%] ?(?=[\r\n]|$)/g, "")
|
|
58
60
|
.trim();
|
|
59
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* 时间戳格式化为 yyyy-MM-dd HH:mm:ss
|
|
64
|
+
* @param ts 毫秒时间戳
|
|
65
|
+
* @returns 格式化时间
|
|
66
|
+
*/
|
|
67
|
+
export function fmtTime(ts) {
|
|
68
|
+
const d = new Date(ts);
|
|
69
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
70
|
+
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
|
71
|
+
}
|
|
60
72
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,uCAAuC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,cAAc,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAA;AACzD,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,uCAAuC;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzC;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,cAAc,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAA;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,GAAW;IAChD,MAAM,aAAa,GAAG,wBAAwB,CAAA;IAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;IACjF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC3G,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,4CAA4C;IAC5C,OAAO,CAAC,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAA;AACvF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAS;IACxC,kDAAkD;IAClD,MAAM,SAAS,GAAG,qBAAqB,CAAA;IACvC,2CAA2C;IAC3C,OAAO,CAAC;SACL,KAAK,CAAC,MAAM,CAAC;SACb,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAA;QAC9D,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC9B,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,OAAO,CAAC;SACL,OAAO,CAAC,kEAAkE,EAAE,EAAE,CAAC;SAC/E,IAAI,EAAE,CAAA;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,EAAU;IAChC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAA;IACtB,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IACnD,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,CAAA;AACnI,CAAC"}
|