@xiaoqiong0v0/opencode-ssh-tool 0.4.0 → 0.5.1

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 (56) hide show
  1. package/README.md +22 -22
  2. package/dist/base-session.d.ts +128 -0
  3. package/dist/base-session.d.ts.map +1 -0
  4. package/dist/base-session.js +414 -0
  5. package/dist/base-session.js.map +1 -0
  6. package/dist/constants.d.ts +27 -3
  7. package/dist/constants.d.ts.map +1 -1
  8. package/dist/constants.js +28 -3
  9. package/dist/constants.js.map +1 -1
  10. package/dist/history.d.ts +14 -5
  11. package/dist/history.d.ts.map +1 -1
  12. package/dist/history.js +25 -9
  13. package/dist/history.js.map +1 -1
  14. package/dist/i18n.d.ts +75 -227
  15. package/dist/i18n.d.ts.map +1 -1
  16. package/dist/i18n.js +65 -211
  17. package/dist/i18n.js.map +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +83 -31
  20. package/dist/index.js.map +1 -1
  21. package/dist/last-match.d.ts +17 -0
  22. package/dist/last-match.d.ts.map +1 -0
  23. package/dist/last-match.js +63 -0
  24. package/dist/last-match.js.map +1 -0
  25. package/dist/local-session.d.ts +9 -91
  26. package/dist/local-session.d.ts.map +1 -1
  27. package/dist/local-session.js +46 -308
  28. package/dist/local-session.js.map +1 -1
  29. package/dist/log.d.ts +3 -0
  30. package/dist/log.d.ts.map +1 -0
  31. package/dist/log.js +5 -0
  32. package/dist/log.js.map +1 -0
  33. package/dist/server.d.ts +32 -5
  34. package/dist/server.d.ts.map +1 -1
  35. package/dist/server.js +417 -349
  36. package/dist/server.js.map +1 -1
  37. package/dist/session.d.ts +15 -108
  38. package/dist/session.d.ts.map +1 -1
  39. package/dist/session.js +69 -361
  40. package/dist/session.js.map +1 -1
  41. package/dist/shell-adapter.d.ts +20 -0
  42. package/dist/shell-adapter.d.ts.map +1 -0
  43. package/dist/shell-adapter.js +70 -0
  44. package/dist/shell-adapter.js.map +1 -0
  45. package/dist/ssh-auth.d.ts.map +1 -1
  46. package/dist/ssh-auth.js +1 -2
  47. package/dist/ssh-auth.js.map +1 -1
  48. package/dist/utils.d.ts +25 -24
  49. package/dist/utils.d.ts.map +1 -1
  50. package/dist/utils.js +279 -45
  51. package/dist/utils.js.map +1 -1
  52. package/dist/web/app.css +43 -0
  53. package/dist/web/app.js +2 -0
  54. package/dist/web/fonts/CaskaydiaCoveNerdFontMono-Regular.ttf +0 -0
  55. package/dist/web/index.html +28 -0
  56. package/package.json +6 -3
package/dist/i18n.js CHANGED
@@ -15,133 +15,14 @@ export function getLang(configured = "en") {
15
15
  }
16
16
  /** 工具描述与参数说明字典 */
17
17
  export const T = {
18
- ssh_connect: {
19
- en: "Open a long-lived SSH connection with a PTY shell in the current session. Reconnecting the same session closes the previous connection first. Returns a connection id.",
20
- zh: "在当前会话建立长驻 SSH 连接并打开 PTY shell;同一会话重复连接会先关闭旧连接。返回连接标识。",
21
- },
22
- ssh_connect_args: {
23
- host: { en: "Target host or IP", zh: "目标主机 host / IP" },
24
- user: { en: "Login username", zh: "登录用户名" },
25
- port: { en: "Port, default 22", zh: "端口,默认 22" },
26
- name: {
27
- en: "Terminal name within the session, default 'default'. Creating with an existing name closes the old one first. Use distinct names to keep multiple terminals.",
28
- zh: "会话内的终端名,默认 'default'。同名创建会先关闭旧终端。用不同名称可保持多个终端。",
29
- },
30
- password: {
31
- en: "Password for password auth (optional). Supports plain text or 'file:<abs path>' to read from a file (avoids exposing it in context). If omitted, falls back to SSH key / agent / SSH_PASSWORD env.",
32
- zh: "密码认证密码(可选)。支持明文或 'file:<绝对路径>' 从文件读取(避免暴露在上下文中)。省略时回退到 SSH 私钥 / agent / 环境变量 SSH_PASSWORD。",
33
- },
34
- },
35
- term_exec: {
36
- en: "Execute a command in an SSH, local or container terminal (by terminal name), preserving cwd and environment. Commands outside the read-only allowlist require user approval.",
37
- zh: "在 SSH / 本地 / 容器终端(按终端名)执行命令,保留 cwd 与环境变量;白名单外的命令需用户审批。",
38
- },
39
- term_exec_args: {
40
- command: { en: "Shell command to execute", zh: "要执行的 shell 命令" },
41
- waitResult: {
42
- en: "Wait for the command to finish and return its output. Default false: submit async, return immediately; read results later via term_read.",
43
- zh: "是否等待命令完成并返回其输出。默认 false:异步提交,立即返回;稍后通过 term_read 读取结果。",
44
- },
45
- name: {
46
- en: "Target terminal name, default 'default'. Must match a name from ssh_connect.",
47
- zh: "目标终端名,默认 'default'。需与 ssh_connect 创建的名称一致。",
48
- },
49
- },
50
18
  submitted: {
51
- en: "Command submitted (async). Running in background: check term_status for completion, then term_read to read output.",
52
- zh: "命令已异步提交,后台执行中:用 term_status 查完成状态,再用 term_read 读取输出。",
53
- },
54
- term_read: {
55
- en: "Read output of an SSH, local or container terminal: buffered (unconsumed, for interactive/polling) or history (completed command+output pairs, first N or last N). Returns browser URL for the full scrollable viewer when the HTTP server is on.",
56
- zh: "读取 SSH / 本地 / 容器终端输出:缓冲(未消费,交互/轮询用)或历史(已完成的命令+输出对,前 N 条或后 N 条)。HTTP 服务开启时返回浏览器查看完整记录的地址。",
57
- },
58
- term_send: {
59
- en: "Send text or keystrokes to an SSH, local or container terminal for interactive prompts (sudo password, confirmations, interrupts). Escapes: \\r or \\n = Enter, \\x03 = Ctrl-C, \\x04 = Ctrl-D, \\x1a = Ctrl-Z, \\x1b = Esc. After sending, read the result with term_read.",
60
- zh: "向 SSH / 本地 / 容器终端发送文本或按键,用于交互提示(sudo 密码、确认、中断等)。转义:\\r 或 \\n = 回车,\\x03 = Ctrl-C,\\x04 = Ctrl-D,\\x1a = Ctrl-Z,\\x1b = Esc。发送后用 term_read 读取结果。",
61
- },
62
- term_send_args: {
63
- text: {
64
- en: "Text or key sequence to send. Use \\r or \\n for Enter, \\x03 for Ctrl-C, \\x1b for Esc. For sudo password prompts send the password followed by \\r.",
65
- zh: "要发送的文本或按键序列。回车用 \\r 或 \\n,Ctrl-C 用 \\x03,Esc 用 \\x1b。sudo 密码提示时发送密码后跟 \\r。",
66
- },
67
- name: {
68
- en: "Target terminal name, default 'default'.",
69
- zh: "目标终端名,默认 'default'。",
70
- },
19
+ en: "Command submitted (async). Running in background: check term_cli status for completion, then term_cli read to read output.",
20
+ zh: "命令已异步提交,后台执行中:用 term_cli status 查完成状态,再用 term_cli read 读取输出。",
71
21
  },
72
22
  send_ok: {
73
23
  en: "Sent: {text}",
74
24
  zh: "已发送:{text}",
75
25
  },
76
- send_title: {
77
- en: "SSH send",
78
- zh: "SSH 发送",
79
- },
80
- term_read_args: {
81
- source: {
82
- en: "Where to read from: 'buffer' (unconsumed live output) or 'history' (completed pairs, default).",
83
- zh: "读取来源:'buffer'(实时未消费输出)或 'history'(已完成消息对,默认)。",
84
- },
85
- lines: { en: "Max lines to read from buffer, all if omitted", zh: "读取缓冲行数上限,默认全部" },
86
- direction: {
87
- en: "Which end to take (history): 'tail' (last N, default) or 'head' (first N). At most N pairs.",
88
- zh: "取哪一端(history):'tail'(最后 N 条,默认)或 'head'(前 N 条)。最多 N 条。",
89
- },
90
- limit: {
91
- en: "Number of pairs to return (history, default 10). Capped at total pairs.",
92
- zh: "返回的对数(history,默认 10)。不超过总对数。",
93
- },
94
- includeCommand: {
95
- en: "Whether to include the command line in history output. Default false (output only).",
96
- zh: "是否在 history 结果中包含命令行。默认 false(只返回输出)。",
97
- },
98
- name: {
99
- en: "Target terminal name, default 'default'.",
100
- zh: "目标终端名,默认 'default'。",
101
- },
102
- },
103
- term_status: {
104
- en: "Check SSH/local/container terminal state (busy, pending, connection) by terminal name (all terminals if omitted) and the HTTP server state (URL/port/session count). Use busy to poll completion instead of reading animated output.",
105
- zh: "按终端名检查 SSH / 本地 / 容器终端状态(busy、未消费量、连接;省略则列出全部终端)及 HTTP 服务状态(URL/端口/会话数)。用 busy 轮询完成情况,避免读取动画中间态。",
106
- },
107
- term_status_args: {
108
- name: {
109
- en: "Terminal name to check; omit to list all terminals.",
110
- zh: "要检查的终端名;省略则列出全部终端。",
111
- },
112
- },
113
- term_disconnect: {
114
- en: "Close the terminal of a name (default 'default') for an SSH, local or container session, or all terminals when name is omitted, and clean up session state.",
115
- zh: "关闭指定名称(默认 'default')的 SSH / 本地 / 容器终端,name 省略则关闭全部终端,并清理会话态。",
116
- },
117
- term_disconnect_args: {
118
- name: {
119
- en: "Terminal name to disconnect; omit to disconnect all terminals.",
120
- zh: "要断开的终端名;省略则断开全部终端。",
121
- },
122
- },
123
- local_connect: {
124
- en: "Start a local/container PTY terminal (e.g. pwsh, bash, docker exec -it <container> sh) in the current session. Same-session reconnect closes the previous one. Uses Bun.Terminal (runs in the opencode Bun runtime).",
125
- zh: "在当前会话启动本地/容器 PTY 终端(如 pwsh、bash、docker exec -it <容器> sh);同一会话重复启动会先关闭旧的。基于 Bun.Terminal(opencode Bun 运行时内运行)。",
126
- },
127
- local_connect_args: {
128
- command: {
129
- en: "Command to launch, e.g. pwsh / bash / docker exec -it <container> sh",
130
- zh: "要启动的命令,如 pwsh / bash / docker exec -it <容器> sh",
131
- },
132
- name: {
133
- en: "Terminal name within the session, default 'default'. Creating with an existing name closes the old one first.",
134
- zh: "会话内的终端名,默认 'default'。同名创建会先关闭旧终端。",
135
- },
136
- cwd: {
137
- en: "Working directory, defaults to plugin cwd.",
138
- zh: "工作目录,默认插件所在目录。",
139
- },
140
- },
141
- local_connect_title_ok: {
142
- en: "Local terminal started",
143
- zh: "本地终端已启动",
144
- },
145
26
  local_connect_ok: {
146
27
  en: "Started: {cmd} (terminal {name})",
147
28
  zh: "已启动:{cmd}(终端 {name})",
@@ -150,18 +31,19 @@ export const T = {
150
31
  en: "Local terminal start failed",
151
32
  zh: "本地终端启动失败",
152
33
  },
153
- ssh_cli: {
154
- en: "Unified CLI tool (CLI style): SSH / local / container terminal sessions. Subcommands: connect / local / exec / read / send / status / disconnect / help. Use 'help' for full usage.",
155
- zh: "统一命令行工具(CLI 风格):SSH/本地/容器终端会话。子命令: connect / local / exec / read / send / status / disconnect / help。用 'help' 查看完整用法。",
34
+ term_cli: {
35
+ en: "Unified terminal CLI: SSH (remote) / local shell (wsl, pwsh, bash) / container (docker exec) sessions. For ANY terminal you already have or can start locally — WSL, Docker containers, or local shells — use the 'local' subcommand INSTEAD of running commands via bash. Subcommands: connect / local / exec / read / send / status / disconnect / help. Use 'help' for full usage.",
36
+ zh: "统一终端命令行工具:SSH(远程)/ 本地 shell(wsl、pwsh、bash)/ 容器(docker exec)会话。对任何本地可启动的终端——WSL、Docker 容器或本地 shell——应使用 'local' 子命令,而不是用 bash 直接执行。子命令: connect / local / exec / read / send / status / disconnect / help。用 'help' 查看完整用法。",
156
37
  },
157
- ssh_cli_args: {
158
- en: "Full command line string, e.g. 'exec \"ls -la\" -w' or 'connect user@host'; defaults to 'help' when empty.",
159
- zh: "完整命令行字符串,如 'exec \"ls -la\" -w' 或 'connect user@host';空时默认 'help'。",
38
+ term_cli_args: {
39
+ en: "Full command line string, e.g. 'local \"wsl bash\"' / 'exec \"ls -la\" -w' / 'connect user@host'; defaults to 'help' when empty.",
40
+ zh: "完整命令行字符串,如 'local \"wsl bash\"' / 'exec \"ls -la\" -w' / 'connect user@host';空时默认 'help'。",
160
41
  },
161
- ssh_cli_help: {
162
- en: `ssh_cli unified CLI tool: manage SSH / local / container terminal sessions.
42
+ term_cli_help: {
43
+ en: `term_cli unified CLI tool: manage SSH / local (wsl, pwsh, bash) / container (docker exec) terminal sessions.
44
+ Use 'local' for any terminal started on this machine (WSL, Docker containers, local shells).
163
45
 
164
- Usage: ssh_cli <subcommand> [args]
46
+ Usage: term_cli <subcommand> [args]
165
47
 
166
48
  Subcommands:
167
49
  connect <target> [-u user] [-n name] [-p password|file:path]
@@ -172,7 +54,7 @@ Subcommands:
172
54
  exec "<command>" [-n name] [-w]
173
55
  run a command in the terminal (default: submit async and return immediately; -w waits for result)
174
56
  read [-n name] [-s buffer|history] [-l limit] [--head] [--include-command]
175
- read terminal output: buffer (live) / history (default tail last N)
57
+ read terminal output: buffer (current snapshot, consumed) / history (default tail last N)
176
58
  send "<text>" [-n name]
177
59
  send text/keystrokes (\\r Enter, \\x03 Ctrl-C, \\x04 Ctrl-D, \\x1a Ctrl-Z, \\x1b Esc)
178
60
  status [-n name]
@@ -183,19 +65,20 @@ Subcommands:
183
65
  show this help
184
66
 
185
67
  Examples:
186
- ssh_cli connect root@192.168.1.10
187
- ssh_cli connect user@host -p file:C:\\secrets\\pw.txt
188
- ssh_cli local "docker exec -it myctr bash" -n db
189
- ssh_cli exec "ls -la" -w
190
- ssh_cli exec "cd /var/log && tail -50 syslog"
191
- ssh_cli send "mypass\\r" -n default
192
- ssh_cli read -n db -s buffer
193
- ssh_cli status
194
- ssh_cli disconnect -n db
68
+ term_cli connect root@192.168.1.10
69
+ term_cli connect user@host -p file:C:\\secrets\\pw.txt
70
+ term_cli local "docker exec -it myctr bash" -n db
71
+ term_cli exec "ls -la" -w
72
+ term_cli exec "cd /var/log && tail -50 syslog"
73
+ term_cli send "mypass\\r" -n default
74
+ term_cli read -n db -s buffer
75
+ term_cli status
76
+ term_cli disconnect -n db
195
77
  `,
196
- zh: `ssh_cli 统一命令行工具:管理 SSH / 本地 / 容器终端会话。
78
+ zh: `term_cli 统一命令行工具:管理 SSH / 本地(wsl、pwsh、bash)/ 容器(docker exec)终端会话。
79
+ 本机可启动的终端(WSL、Docker 容器、本地 shell)一律用 'local' 子命令。
197
80
 
198
- 用法: ssh_cli <子命令> [参数]
81
+ 用法: term_cli <子命令> [参数]
199
82
 
200
83
  子命令:
201
84
  connect <target> [-u user] [-n name] [-p password|file:path]
@@ -206,7 +89,7 @@ Examples:
206
89
  exec "<command>" [-n name] [-w]
207
90
  在指定终端执行命令(默认异步提交立即返回;-w 同步等待结果)
208
91
  read [-n name] [-s buffer|history] [-l limit] [--head] [--include-command]
209
- 读终端输出:buffer 实时 / history 历史(默认 tail 后 N 条)
92
+ 读终端输出:buffer 实时快照(读取后清空)/ history 历史快照(默认 tail 后 N 条)
210
93
  send "<text>" [-n name]
211
94
  发送文本/按键(\\r 回车、\\x03 Ctrl-C、\\x04 Ctrl-D、\\x1a Ctrl-Z、\\x1b Esc)
212
95
  status [-n name]
@@ -217,15 +100,15 @@ Examples:
217
100
  显示本帮助
218
101
 
219
102
  示例:
220
- ssh_cli connect root@192.168.1.10
221
- ssh_cli connect user@host -p file:C:\\secrets\\pw.txt
222
- ssh_cli local "docker exec -it myctr bash" -n db
223
- ssh_cli exec "ls -la" -w
224
- ssh_cli exec "cd /var/log && tail -50 syslog"
225
- ssh_cli send "mypass\\r" -n default
226
- ssh_cli read -n db -s buffer
227
- ssh_cli status
228
- ssh_cli disconnect -n db
103
+ term_cli connect root@192.168.1.10
104
+ term_cli connect user@host -p file:C:\\secrets\\pw.txt
105
+ term_cli local "docker exec -it myctr bash" -n db
106
+ term_cli exec "ls -la" -w
107
+ term_cli exec "cd /var/log && tail -50 syslog"
108
+ term_cli send "mypass\\r" -n default
109
+ term_cli read -n db -s buffer
110
+ term_cli status
111
+ term_cli disconnect -n db
229
112
  `,
230
113
  },
231
114
  denied: {
@@ -286,8 +169,8 @@ Examples:
286
169
  zh: "危险命令,已拒绝执行。",
287
170
  },
288
171
  not_connected: {
289
- en: "No SSH session. Please run ssh_connect first.",
290
- zh: "未建立 SSH 会话,请先调用 ssh_connect。",
172
+ en: "No active terminal. Use term_cli connect (SSH) or term_cli local first.",
173
+ zh: "无活动终端。请先用 term_cli connect(SSH)或 term_cli local 建立。",
291
174
  },
292
175
  rejected_connect: {
293
176
  en: "Connection rejected.",
@@ -298,12 +181,8 @@ Examples:
298
181
  zh: "终端名非法。仅允许字母、数字、下划线、中划线、点(最多 64 字符),不得含路径分隔符。",
299
182
  },
300
183
  no_sessions: {
301
- en: "No active SSH sessions.",
302
- zh: "当前没有活动的 SSH 会话。",
303
- },
304
- connect_title_ok: {
305
- en: "SSH connected",
306
- zh: "SSH 已连接",
184
+ en: "No active terminals.",
185
+ zh: "当前没有活动的终端会话。",
307
186
  },
308
187
  connect_ok: {
309
188
  en: "Connected: {user}@{host}:{port} (session {sid}, terminal {name})",
@@ -317,41 +196,21 @@ Examples:
317
196
  en: "Unknown error",
318
197
  zh: "未知错误",
319
198
  },
320
- exec_title: {
321
- en: "SSH exec: {cmd}",
322
- zh: "SSH 执行: {cmd}",
323
- },
324
199
  exec_failed: {
325
200
  en: "Execution failed",
326
201
  zh: "执行失败",
327
202
  },
328
- session_output_title: {
329
- en: "SSH session output",
330
- zh: "SSH 会话输出",
331
- },
332
203
  session_disconnected: {
333
- en: "SSH session disconnected",
334
- zh: "SSH 会话已断开",
204
+ en: "Terminal disconnected",
205
+ zh: "终端已断开",
335
206
  },
336
207
  status_busy_hint: {
337
- en: "\nHint: a command is still running. Wait and retry, or call term_read for partial output.",
338
- zh: "\n提示:仍有命令在执行,请等待后重试或调用 term_read 获取部分输出。",
208
+ en: "\nHint: a command is still running. Wait and retry, or call term_cli read for partial output.",
209
+ zh: "\n提示:仍有命令在执行,请等待后重试或调用 term_cli read 获取部分输出。",
339
210
  },
340
211
  status_idle_hint: {
341
- en: "\nHint: no command running. You can safely execute a new command or call term_read for remaining output.",
342
- zh: "\n提示:无命令在执行,可安全执行新命令或调用 term_read 读取剩余输出。",
343
- },
344
- status_title: {
345
- en: "SSH session status",
346
- zh: "SSH 会话状态",
347
- },
348
- server_title: {
349
- en: "SSH HTTP server",
350
- zh: "SSH HTTP 服务",
351
- },
352
- server_info: {
353
- en: "HTTP server enabled\nurl: {url}\nport: {port}\nactive sessions: {n}\nOpen {url} in a browser to view terminal records (scrollable, auto-refreshing).",
354
- zh: "HTTP 服务已启用\nurl: {url}\nport: {port}\n活跃会话: {n}\n浏览器访问 {url} 查看终端记录(可滚动、自动刷新)。",
212
+ en: "\nHint: no command running. You can safely execute a new command or call term_cli read for remaining output.",
213
+ zh: "\n提示:无命令在执行,可安全执行新命令或调用 term_cli read 读取剩余输出。",
355
214
  },
356
215
  browser_full_record: {
357
216
  en: "\nBrowser full record: {url}",
@@ -362,12 +221,12 @@ Examples:
362
221
  zh: "\n(HTTP 服务未启用)",
363
222
  },
364
223
  history_title: {
365
- en: "SSH history (last {n} / total {total})",
366
- zh: "SSH 历史(最后 {n} 条 / 共 {total} 条)",
224
+ en: "Terminal history (last {n} / total {total})",
225
+ zh: "终端历史(最后 {n} 条 / 共 {total} 条)",
367
226
  },
368
227
  history_title_head: {
369
- en: "SSH history (first {n} / total {total})",
370
- zh: "SSH 历史(前 {n} 条 / 共 {total} 条)",
228
+ en: "Terminal history (first {n} / total {total})",
229
+ zh: "终端历史(前 {n} 条 / 共 {total} 条)",
371
230
  },
372
231
  web_title: { en: "Terminal Records", zh: "终端记录" },
373
232
  web_loading: { en: "Loading...", zh: "加载中..." },
@@ -378,37 +237,32 @@ Examples:
378
237
  web_local: { en: "local", zh: "本地" },
379
238
  web_commands: { en: "commands", zh: "条命令" },
380
239
  web_auto_refresh: { en: "auto-refresh every 2s", zh: "每 2s 自动刷新" },
381
- web_no_session: { en: "No session. Use ssh_cli connect first.", zh: "无会话,请先用 ssh_cli connect 建立连接。" },
240
+ web_no_session: { en: "No terminal. Use term_cli connect (SSH) or term_cli local first.", zh: "无终端会话,请先用 term_cli connect(SSH)或 term_cli local 建立。" },
382
241
  web_running: { en: "[running] ", zh: "[运行中] " },
383
242
  web_new_messages: { en: "↓ New messages", zh: "↓ 新消息" },
243
+ web_delete_terminal: { en: "Delete disconnected terminal", zh: "删除已断开终端" },
244
+ web_cmd_placeholder: { en: "Enter command (Shift+Enter new line)", zh: "输入命令(Shift+Enter 换行)" },
245
+ web_send_ctrlc: { en: "Keystroke", zh: "快捷键" },
384
246
  disconnected_ok: {
385
- en: "SSH connection closed ({host}).",
386
- zh: "SSH 连接已断开({host})。",
247
+ en: "Terminal closed ({host}).",
248
+ zh: "终端已断开({host})。",
249
+ },
250
+ disconnected_ok_local: {
251
+ en: "Terminal closed ({program}).",
252
+ zh: "终端已断开({program})。",
387
253
  },
388
254
  disconnected_all_ok: {
389
- en: "All SSH terminals closed (last host {host}).",
390
- zh: "已断开全部 SSH 终端(最后主机 {host})。",
255
+ en: "All terminals closed (last host {host}).",
256
+ zh: "已断开全部终端(最后主机 {host})。",
257
+ },
258
+ disconnected_all_ok_local: {
259
+ en: "All terminals closed (last program {program}).",
260
+ zh: "已断开全部终端(最后程序 {program})。",
391
261
  },
392
262
  err_not_connected: {
393
263
  en: "Not connected",
394
264
  zh: "未连接",
395
265
  },
396
- err_busy: {
397
- en: "Previous command still running, poll with term_status first",
398
- zh: "上一条命令仍在执行,请先 term_status 轮询",
399
- },
400
- err_shell_open: {
401
- en: "Shell open failed",
402
- zh: "shell 打开失败",
403
- },
404
- err_no_such_session: {
405
- en: "Session not found or disconnected",
406
- zh: "会话不存在或已断开",
407
- },
408
- truncated: {
409
- en: "... [output truncated, {n} chars total]",
410
- zh: "... [输出已截断,共 {n} 字符]",
411
- },
412
266
  };
413
267
  /** 取某语言下的一条文案 */
414
268
  export function tr(key, lang) {
package/dist/i18n.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;AA6MvD,eAAO,MAAM,eAAe,EAAE,MA8R7B,CAAA;eAGc,eAAe"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAgNvD,eAAO,MAAM,eAAe,EAAE,MAyU7B,CAAA;eAGc,eAAe"}
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { tool } from "@opencode-ai/plugin";
3
3
  import stringArgv from "string-argv";
4
4
  import { parseArgs } from "node:util";
5
- import createLogger from "@xiaoqiong0v0/opencode-plugin-logger";
5
+ import log from "./log.js";
6
6
  import { CACHE_DIR } from "./constants.js";
7
7
  import { homedir } from "node:os";
8
8
  import { join } from "node:path";
@@ -10,13 +10,13 @@ import { rmSync } from "node:fs";
10
10
  import { loadConfig } from "./config.js";
11
11
  import { SessionHistory } from "./history.js";
12
12
  import { T, getLang, tr } from "./i18n.js";
13
+ import { toModelText } from "./utils.js";
13
14
  import { createDecider } from "./permission.js";
14
15
  import { SshSession } from "./session.js";
15
16
  import { LocalSession } from "./local-session.js";
16
17
  import {} from "./server.js";
17
18
  import { ensureServer } from "./server-manager.js";
18
19
  import { writeSessionState, removeSessionState, removeAllSessionStates } from "./session-store.js";
19
- const log = createLogger("opencode-ssh-tool");
20
20
  /** 默认终端名(不传 name 时用) */
21
21
  const DEFAULT_NAME = "default";
22
22
  /** 终端名合法字符(字母/数字/下划线/中划线/点),防止路径穿越 */
@@ -68,13 +68,18 @@ function getSessionMap(sessionID) {
68
68
  function getSession(sessionID, name = DEFAULT_NAME) {
69
69
  return getSessionMap(sessionID)?.get(name);
70
70
  }
71
- /** 扁平化会话条目列表(供 HTTP 服务展示) */
71
+ /** 扁平化会话条目列表(供 HTTP 服务展示,SSH + 本地/容器,kind 区分历史目录与展示) */
72
72
  function listSessionEntries() {
73
73
  const entries = [];
74
74
  for (const [sessionID, map] of sshSessions) {
75
75
  const meta = sessionMeta.get(sessionID);
76
76
  for (const [name, session] of map)
77
- entries.push({ sessionID, name, session, title: meta?.title, directory: meta?.directory });
77
+ entries.push({ sessionID, name, session, kind: "ssh", title: meta?.title, directory: meta?.directory });
78
+ }
79
+ for (const [sessionID, map] of localSessions) {
80
+ const meta = sessionMeta.get(sessionID);
81
+ for (const [name, session] of map)
82
+ entries.push({ sessionID, name, session, kind: "local", title: meta?.title, directory: meta?.directory });
78
83
  }
79
84
  return entries;
80
85
  }
@@ -193,6 +198,27 @@ function cleanupAllSessions(sessionID) {
193
198
  }
194
199
  }
195
200
  export const OpenCodeSshTool = async () => {
201
+ // 父子会话关系(sessionID → parentID;根的 parentID 为 undefined)
202
+ // 通过 session.created/updated 事件构建,用于根系查找(主子会话共享终端)
203
+ const childMap = new Map();
204
+ /**
205
+ * 沿 parentID 链找到根会话 ID(主子会话共享存储key)
206
+ * 输出异常时回退回原 sessionID
207
+ */
208
+ const findRoot = (sessionID) => {
209
+ let cur = sessionID;
210
+ const visited = new Set();
211
+ while (cur && !visited.has(cur)) {
212
+ visited.add(cur);
213
+ const parent = childMap.get(cur);
214
+ if (parent !== undefined && parent !== null) {
215
+ cur = parent;
216
+ continue;
217
+ }
218
+ break;
219
+ }
220
+ return cur;
221
+ };
196
222
  log.loaded();
197
223
  // 加载配置并启动 HTTP 终端记录服务(默认开启;端口 0=自动分配)
198
224
  const cfg = loadConfig();
@@ -223,9 +249,9 @@ export const OpenCodeSshTool = async () => {
223
249
  else {
224
250
  log.info("HTTP 服务未启用(配置 server.enabled=false)");
225
251
  }
226
- // ===== CLI 风格单工具(ssh_cli)子命令实现 =====
252
+ // ===== CLI 风格单工具(term_cli)子命令实现 =====
227
253
  /** 完整用法(模型自学手册) */
228
- const HELP_TEXT = tr("ssh_cli_help", lang);
254
+ const HELP_TEXT = tr("term_cli_help", lang);
229
255
  /** connect:SSH 连接(target=user@host[:port]) */
230
256
  async function doConnect(args, ctx) {
231
257
  const { values, positionals } = parseArgs({ args, options: { name: { type: "string", short: "n" }, password: { type: "string", short: "p" }, user: { type: "string", short: "u" } }, allowPositionals: true });
@@ -321,8 +347,10 @@ export const OpenCodeSshTool = async () => {
321
347
  return tr("denied", lang);
322
348
  }
323
349
  }
350
+ const name = values.name ?? DEFAULT_NAME;
351
+ syncSessionState(ctx.sessionID, name);
324
352
  const result = values.waitResult ? await session.exec(command) : await session.submit(command);
325
- syncSessionState(ctx.sessionID, values.name ?? DEFAULT_NAME);
353
+ syncSessionState(ctx.sessionID, name);
326
354
  log.tool("term_exec", { command, ok: result.ok, submitted: result.submitted, interactive: result.interactive, running: result.running });
327
355
  if (result.submitted)
328
356
  return tr("submitted", lang);
@@ -345,7 +373,7 @@ export const OpenCodeSshTool = async () => {
345
373
  const direction = values.head ? "head" : "tail";
346
374
  const selected = direction === "tail" ? all.slice(-limit) : all.slice(0, limit);
347
375
  const includeCommand = values.includeCommand ?? false;
348
- const text = selected.map((p) => (includeCommand ? `$ ${p.command}\n${history.readOutput(p)}` : history.readOutput(p))).join("\n");
376
+ const text = selected.map((p) => (includeCommand ? `$ ${p.command}\n` : "") + toModelText(history.readOutput(p))).join("\n");
349
377
  const browserLine = httpUrl ? tr("browser_full_record", lang).replace("{url}", httpUrl) : tr("server_not_enabled", lang);
350
378
  return `${tr(direction === "tail" ? "history_title" : "history_title_head", lang).replace("{n}", String(selected.length)).replace("{total}", String(all.length))}\n${text}${browserLine}`;
351
379
  }
@@ -417,10 +445,13 @@ export const OpenCodeSshTool = async () => {
417
445
  if ((!smap || smap.size === 0) && (!lmap || lmap.size === 0))
418
446
  return tr("no_sessions", lang);
419
447
  if (!values.name) {
420
- const firstHost = [...(smap?.values() ?? [])][0]?.getStatus().host;
448
+ const firstSshHost = [...(smap?.values() ?? [])][0]?.getStatus().host;
449
+ const firstLocalProgram = [...(lmap?.values() ?? [])][0]?.getStatus().program;
421
450
  cleanupAllSessions(ctx.sessionID);
422
451
  cleanupAllLocalSessions(ctx.sessionID);
423
- return tr("disconnected_all_ok", lang).replace("{host}", firstHost ?? "-");
452
+ if (firstSshHost)
453
+ return tr("disconnected_all_ok", lang).replace("{host}", firstSshHost);
454
+ return tr("disconnected_all_ok_local", lang).replace("{program}", firstLocalProgram ?? "-");
424
455
  }
425
456
  const ssh = getSession(ctx.sessionID, values.name);
426
457
  if (ssh) {
@@ -432,7 +463,7 @@ export const OpenCodeSshTool = async () => {
432
463
  if (local) {
433
464
  const program = local.getStatus().program;
434
465
  cleanupLocalSession(ctx.sessionID, values.name);
435
- return tr("disconnected_ok", lang).replace("{host}", program ?? "-");
466
+ return tr("disconnected_ok_local", lang).replace("{program}", program ?? "-");
436
467
  }
437
468
  return tr("no_sessions", lang);
438
469
  }
@@ -442,52 +473,73 @@ export const OpenCodeSshTool = async () => {
442
473
  const [cmd, ...rest] = tokens;
443
474
  if (!cmd || cmd === "help")
444
475
  return HELP_TEXT;
476
+ // 统一按根会话 ID 路由(主子会话共享终端)
477
+ const rootID = await findRoot(ctx.sessionID);
478
+ const rootCtx = { ...ctx, sessionID: rootID };
445
479
  switch (cmd) {
446
- case "connect": return doConnect(rest, ctx);
447
- case "local": return doLocal(rest, ctx);
448
- case "exec": return doExec(rest, ctx);
449
- case "read": return doRead(rest, ctx);
450
- case "send": return doSend(rest, ctx);
451
- case "status": return doStatus(rest, ctx);
452
- case "disconnect": return doDisconnect(rest, ctx);
480
+ case "connect": return doConnect(rest, rootCtx);
481
+ case "local": return doLocal(rest, rootCtx);
482
+ case "exec": return doExec(rest, rootCtx);
483
+ case "read": return doRead(rest, rootCtx);
484
+ case "send": return doSend(rest, rootCtx);
485
+ case "status": return doStatus(rest, rootCtx);
486
+ case "disconnect": return doDisconnect(rest, rootCtx);
453
487
  default: return `${tr("cli_unknown", lang).replace("{cmd}", cmd)}\n\n${HELP_TEXT}`;
454
488
  }
455
489
  }
490
+ // 记录哪些根会话已收到过"来自根自身"的标题(防止子会话标题覆盖根标题)
491
+ const rootTitleOwned = new Set();
456
492
  return {
457
493
  event: async ({ event }) => {
458
494
  // 会话创建/更新时记录标题与目录(供 HTTP 页面显示会话名称)
459
495
  if (event.type === "session.created" || event.type === "session.updated") {
460
496
  const info = event.properties?.info;
461
497
  if (info?.id) {
462
- sessionMeta.set(info.id, { title: info.title ?? "", directory: info.directory ?? "" });
463
- // 有活动终端时同步标题/目录到状态文件(供跨进程聚合)
464
- const map = getSessionMap(info.id);
498
+ // 记录父子关系(用于根系查找)
499
+ if (info.parentID !== undefined)
500
+ childMap.set(info.id, info.parentID);
501
+ else if (!childMap.has(info.id))
502
+ childMap.set(info.id, undefined);
503
+ // 标题仅来自根会话自身;子会话不覆盖根标题
504
+ const root = findRoot(info.id);
505
+ if (info.id === root) {
506
+ sessionMeta.set(root, { title: info.title ?? "", directory: info.directory ?? "" });
507
+ rootTitleOwned.add(root);
508
+ }
509
+ else if (!rootTitleOwned.has(root) && !sessionMeta.has(root)) {
510
+ sessionMeta.set(root, { title: info.title ?? "", directory: info.directory ?? "" });
511
+ }
512
+ // 有活动终端时同步状态文件
513
+ const map = getSessionMap(root);
465
514
  if (map)
466
515
  for (const name of map.keys())
467
- syncSessionState(info.id, name);
516
+ syncSessionState(root, name);
468
517
  }
469
518
  }
470
- // 会话删除时清理:关闭全部终端连接 + 删缓存目录 + 删元信息
471
519
  if (event.type === "session.deleted") {
472
520
  const props = event.properties;
473
- // sessionID 直接挂在 properties 层(完整事件);info.id 为兜底
474
521
  const sid = props?.sessionID ?? props?.info?.id;
475
522
  if (sid) {
476
- cleanupAllSessions(sid);
477
- cleanupAllLocalSessions(sid);
523
+ childMap.delete(sid);
524
+ const root = findRoot(sid);
525
+ if (root === sid) {
526
+ cleanupAllSessions(sid);
527
+ cleanupAllLocalSessions(sid);
528
+ }
478
529
  sessionMeta.delete(sid);
479
- log.info(`会话 ${sid} 删除,已清理`);
530
+ rootTitleOwned.delete(sid);
531
+ log.info(`会话 ${sid} 删除,根 ${root} 清理`);
480
532
  }
481
533
  }
482
534
  },
483
535
  tool: {
484
- ssh_cli: tool({
485
- description: T.ssh_cli[lang],
536
+ term_cli: tool({
537
+ description: T.term_cli[lang],
486
538
  args: {
487
- args: tool.schema.string().optional().describe(T.ssh_cli_args[lang]),
539
+ args: tool.schema.string().optional().describe(T.term_cli_args[lang]),
488
540
  },
489
541
  async execute(args, context) {
490
- return { title: "ssh_cli", output: await handleCliCommand(args.args ?? "help", context) };
542
+ return { title: "term_cli", output: await handleCliCommand(args.args ?? "help", context) };
491
543
  },
492
544
  }),
493
545
  },