@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/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
- const text = readHistoryFromFile(dir, sid, name);
50
- if (text === null) {
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
- // 渲染命令+输出消息对(保留 ANSI 颜色,前端解析着色)
60
- const lines = [];
61
- for (const pair of entry.session.getHistory().getPairs()) {
62
- lines.push(`$ ${pair.command}`);
63
- lines.push(entry.session.getHistory().readOutput(pair));
64
- }
65
- // 附加运行中命令的实时进度(busy 时)
66
- const running = entry.session.getRunningOutput();
67
- if (running) {
68
- lines.push("");
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": "text/plain; charset=utf-8" });
72
- res.end(lines.join("\n"));
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 渲染文本(命令+输出,去除 ANSI);目录不存在返回 null
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 lines = [];
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
- lines.push(`$ ${data.command}`);
120
+ out.push({ type: "cmd", ts: data.ts ?? Date.now(), text: data.command });
121
121
  if (typeof data.output === "string")
122
- lines.push(data.output);
122
+ out.push({ type: "out", text: data.output });
123
123
  }
124
124
  catch {
125
125
  /* 跳过损坏文件 */
126
126
  }
127
127
  }
128
- return lines.join("\n");
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>SSH 终端记录</h1>
149
- <select id="session" onchange="onSessionChange()"></select>
150
- <select id="terminal" onchange="loadTranscript()"></select>
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 text = await r.text();
267
- pre.innerHTML = ansiToHtml(text);
268
- document.getElementById("meta").textContent = sid + "/" + name + " · " + text.length + " 字符 · 每 2s 自动刷新";
269
- if (stickToBottom) pre.scrollTop = pre.scrollHeight;
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();
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -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;AAmBhC,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"}
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
@@ -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;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG1D;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"}
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;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,GAAW;IAChD,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,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC9E,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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaoqiong0v0/opencode-ssh-tool",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "长驻交互式 SSH 会话工具插件,远程命令受 opencode 权限管控",
6
6
  "files": [