@xiaoqiong0v0/opencode-ssh-tool 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js ADDED
@@ -0,0 +1,179 @@
1
+ // 本地 HTTP 服务:浏览器直接查看可滚动终端记录(默认开启,端口可配,0=随机分配)
2
+ import { createServer } from "node:http";
3
+ import { cleanAnsi } from "./utils.js";
4
+ /**
5
+ * 启动 HTTP 服务(监听 127.0.0.1)
6
+ * @param port 端口,0 或未指定 → 系统随机分配(避免冲突)
7
+ * @param getSessions 获取扁平会话条目列表的函数(供页面展示)
8
+ * @returns 服务句柄(含实际端口与 URL)
9
+ */
10
+ export function startServer(port, getSessions) {
11
+ let actualPort = port;
12
+ const server = createServer((req, res) => {
13
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
14
+ const path = url.pathname;
15
+ if (path === "/health") {
16
+ res.writeHead(200, { "Content-Type": "application/json" });
17
+ res.end(JSON.stringify({ ok: true }));
18
+ return;
19
+ }
20
+ if (path === "/api/status") {
21
+ const entries = getSessions();
22
+ // 按 sessionID 分组(一个会话下多个终端)
23
+ const bySession = new Map();
24
+ for (const { sessionID, name, session, title, directory } of entries) {
25
+ const st = session.getStatus();
26
+ if (!bySession.has(sessionID))
27
+ bySession.set(sessionID, { title, directory, terminals: [] });
28
+ bySession.get(sessionID).terminals.push({ name, host: st.host, user: st.user, port: st.port, connected: st.connected, busy: st.busy, pending: st.pending });
29
+ }
30
+ const sessions = [...bySession.entries()].map(([sessionID, v]) => ({
31
+ sessionID,
32
+ title: v.title,
33
+ directory: v.directory,
34
+ terminals: v.terminals,
35
+ }));
36
+ res.writeHead(200, { "Content-Type": "application/json" });
37
+ res.end(JSON.stringify({ port: actualPort, sessions }));
38
+ return;
39
+ }
40
+ if (path === "/api/transcript") {
41
+ const sid = url.searchParams.get("session") ?? "";
42
+ const name = url.searchParams.get("name") ?? "default";
43
+ const entry = getSessions().find((e) => e.sessionID === sid && e.name === name);
44
+ if (!entry) {
45
+ res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
46
+ res.end("Session not found or disconnected");
47
+ return;
48
+ }
49
+ // 渲染命令+输出消息对
50
+ const lines = [];
51
+ for (const pair of entry.session.getHistory().getPairs()) {
52
+ lines.push(`$ ${pair.command}`);
53
+ lines.push(cleanAnsi(entry.session.getHistory().readOutput(pair)));
54
+ }
55
+ // 附加运行中命令的实时进度(busy 时)
56
+ const running = entry.session.getRunningOutput();
57
+ if (running) {
58
+ lines.push("");
59
+ lines.push(`[ 运行中 ] ${running}`);
60
+ }
61
+ res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
62
+ res.end(lines.join("\n"));
63
+ return;
64
+ }
65
+ if (path === "/") {
66
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
67
+ res.end(renderPage());
68
+ return;
69
+ }
70
+ res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
71
+ res.end("Not Found");
72
+ });
73
+ return new Promise((resolve, reject) => {
74
+ server.once("error", reject);
75
+ server.listen(port, "127.0.0.1", () => {
76
+ const addr = server.address();
77
+ actualPort = addr.port;
78
+ server.removeListener("error", reject);
79
+ resolve({
80
+ server,
81
+ port: actualPort,
82
+ url: `http://127.0.0.1:${actualPort}`,
83
+ close: () => server.close(),
84
+ });
85
+ });
86
+ });
87
+ }
88
+ /** 渲染终端记录页面(黑底绿字等宽,JS 轮询自动刷新) */
89
+ function renderPage() {
90
+ return `<!DOCTYPE html>
91
+ <html lang="zh">
92
+ <head>
93
+ <meta charset="utf-8">
94
+ <title>SSH 终端记录</title>
95
+ <style>
96
+ html, body { margin: 0; height: 100%; background: #0d1117; color: #c9d1d9; font-family: system-ui, sans-serif; }
97
+ header { position: sticky; top: 0; display: flex; align-items: center; gap: 12px; padding: 10px 16px; background: #161b22; border-bottom: 1px solid #30363d; }
98
+ header h1 { margin: 0; font-size: 14px; color: #e6edf3; font-weight: 600; }
99
+ select { background: #21262d; color: #c9d1d9; border: 1px solid #30363d; padding: 4px 8px; border-radius: 6px; }
100
+ 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: #2fbf71; }
101
+ #meta { font-size: 12px; color: #8b949e; }
102
+ </style>
103
+ </head>
104
+ <body>
105
+ <header>
106
+ <h1>SSH 终端记录</h1>
107
+ <select id="session" onchange="onSessionChange()"></select>
108
+ <select id="terminal" onchange="loadTranscript()"></select>
109
+ <span id="meta"></span>
110
+ </header>
111
+ <pre id="term">加载中...</pre>
112
+ <script>
113
+ let sessionsData = [];
114
+
115
+ function sessionLabel(s) {
116
+ // 优先显示会话标题,其次 host@user,最后短 sessionID
117
+ if (s.title && s.title.trim()) return s.title;
118
+ const t = s.terminals && s.terminals[0];
119
+ if (t && t.host) return (t.user ? t.user + "@" : "") + t.host;
120
+ return s.sessionID.slice(0, 8) + "…";
121
+ }
122
+
123
+ async function loadSessions() {
124
+ const r = await fetch("/api/status");
125
+ const data = await r.json();
126
+ sessionsData = data.sessions || [];
127
+ const sel = document.getElementById("session");
128
+ const prev = sel.value;
129
+ sel.innerHTML = "";
130
+ for (const s of sessionsData) {
131
+ const opt = document.createElement("option");
132
+ opt.value = s.sessionID;
133
+ opt.textContent = sessionLabel(s) + " (" + s.terminals.length + " 终端)";
134
+ sel.appendChild(opt);
135
+ }
136
+ if (prev && [...sel.options].some(o => o.value === prev)) sel.value = prev;
137
+ else sel.selectedIndex = sessionsData.length ? 0 : -1;
138
+ onSessionChange();
139
+ }
140
+
141
+ function onSessionChange() {
142
+ const sel = document.getElementById("session");
143
+ const sid = sel.value;
144
+ const tsel = document.getElementById("terminal");
145
+ const prev = tsel.value;
146
+ tsel.innerHTML = "";
147
+ const s = sessionsData.find(x => x.sessionID === sid);
148
+ for (const t of (s ? s.terminals : [])) {
149
+ const opt = document.createElement("option");
150
+ opt.value = t.name || "default";
151
+ opt.textContent = (t.name || "default") + " " + (t.connected ? "●" : "○") + (t.busy ? " ⏳" : "");
152
+ tsel.appendChild(opt);
153
+ }
154
+ if (prev && [...tsel.options].some(o => o.value === prev)) tsel.value = prev;
155
+ else tsel.selectedIndex = tsel.options.length ? 0 : -1;
156
+ loadTranscript();
157
+ }
158
+
159
+ async function loadTranscript() {
160
+ const sel = document.getElementById("session");
161
+ const tsel = document.getElementById("terminal");
162
+ const sid = sel.value;
163
+ const name = tsel.value;
164
+ if (!sid || !name) { document.getElementById("term").textContent = "无会话,请先 ssh_connect"; return; }
165
+ const r = await fetch("/api/transcript?session=" + encodeURIComponent(sid) + "&name=" + encodeURIComponent(name));
166
+ const text = await r.text();
167
+ document.getElementById("term").textContent = text;
168
+ document.getElementById("meta").textContent = sid + "/" + name + " · " + text.length + " 字符 · 每 2s 自动刷新";
169
+ document.getElementById("term").scrollTop = document.getElementById("term").scrollHeight;
170
+ }
171
+
172
+ loadSessions();
173
+ setInterval(loadTranscript, 2000);
174
+ setInterval(loadSessions, 5000);
175
+ </script>
176
+ </body>
177
+ </html>`;
178
+ }
179
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ import { SessionHistory } from "./history.js";
2
+ /** 连接结果 */
3
+ export interface ConnectResult {
4
+ ok: boolean;
5
+ host?: string;
6
+ user?: string;
7
+ port?: number;
8
+ error?: string;
9
+ }
10
+ /** 命令执行结果 */
11
+ export interface ExecResult {
12
+ ok: boolean;
13
+ output: string;
14
+ interactive?: boolean;
15
+ running?: boolean;
16
+ timeout?: boolean;
17
+ /** 异步提交成功(命令后台执行中) */
18
+ submitted?: boolean;
19
+ error?: string;
20
+ host?: string;
21
+ command?: string;
22
+ duration?: number;
23
+ }
24
+ /** 会话状态(供 ssh_status) */
25
+ export interface SessionStatus {
26
+ connected: boolean;
27
+ busy: boolean;
28
+ pending: number;
29
+ name?: string;
30
+ host?: string;
31
+ user?: string;
32
+ port?: number;
33
+ lastActive?: number;
34
+ connectedAt?: number;
35
+ }
36
+ export declare class SshSession {
37
+ private readonly sessionID;
38
+ private readonly name;
39
+ private _client;
40
+ private _stream;
41
+ private _connected;
42
+ private _remoteBusy;
43
+ private _buffer;
44
+ private _host;
45
+ private _user;
46
+ private _port;
47
+ private _connectedAt;
48
+ private _lastActive;
49
+ private _runningStartPos;
50
+ private _runningSentinel;
51
+ private _runningCommand;
52
+ private _watchTimer;
53
+ private _closed;
54
+ private readonly _history;
55
+ constructor(sessionID: string, history: SessionHistory, name?: string);
56
+ /**
57
+ * 建立 SSH 连接并打开 PTY shell
58
+ * @param opts 连接参数
59
+ * @returns 连接结果
60
+ */
61
+ connect(opts: {
62
+ host: string;
63
+ user: string;
64
+ port?: number;
65
+ }): Promise<ConnectResult>;
66
+ /**
67
+ * 异步提交命令:立即返回,命令后台执行,输出由后台监听收集进 history
68
+ * @param command 命令
69
+ * @returns 提交结果(立即返回,不等待命令完成)
70
+ */
71
+ submit(command: string): Promise<ExecResult>;
72
+ /**
73
+ * 在当前会话执行命令(哨兵法,同步等待),保留 cwd/环境
74
+ * @param command 命令
75
+ * @param timeout 超时毫秒,默认 30s
76
+ * @returns 执行结果
77
+ */
78
+ exec(command: string, timeout?: number): Promise<ExecResult>;
79
+ /**
80
+ * 读取并清空未消费缓冲(交互/轮询场景)
81
+ * @returns 未消费输出
82
+ */
83
+ readBuffer(): Promise<{
84
+ ok: boolean;
85
+ output: string;
86
+ error?: string;
87
+ }>;
88
+ /**
89
+ * 获取会话状态(供 ssh_status)
90
+ * @returns 状态对象
91
+ */
92
+ getStatus(): SessionStatus;
93
+ /**
94
+ * 获取会话消息对记录(供 ssh_terminal / HTTP 页面渲染)
95
+ * @returns 消息对存储
96
+ */
97
+ getHistory(): SessionHistory;
98
+ /**
99
+ * 获取当前运行中命令的实时缓冲(合并覆盖后,不消费 buffer)
100
+ * @returns 运行中命令的当前进度文本;无运行命令则返回空串
101
+ */
102
+ getRunningOutput(): string;
103
+ /**
104
+ * 关闭连接,清理会话态(幂等)
105
+ */
106
+ close(): void;
107
+ /**
108
+ * 追加输出到未消费 buffer,超限时截断头部(保留尾部)并修正运行索引
109
+ * @param text 新增输出文本
110
+ */
111
+ private _appendBuffer;
112
+ private _waitSentinel;
113
+ /** 后台哨兵监听:轮询到哨兵 → 收集输出进 history + busy=false,供 ssh_status/ssh_terminal 读取 */
114
+ private _startBackgroundWatch;
115
+ /** 在缓冲中定位哨兵行起始位置(哨兵串开头,容忍行前 ANSI bracketed-paste 序列) */
116
+ private _findSentinel;
117
+ /** 清理后台运行上下文 */
118
+ private _clearRunningContext;
119
+ /** 输出截断保护 */
120
+ private _truncate;
121
+ }
122
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}