@electerm/electerm-react 5.3.15 → 5.5.6

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 (149) hide show
  1. package/README.md +246 -12
  2. package/client/common/choose-save-folder.js +21 -2
  3. package/client/common/constants.js +23 -6
  4. package/client/common/create-title.jsx +6 -0
  5. package/client/common/default-setting.js +14 -0
  6. package/client/common/init-setting-item.js +5 -0
  7. package/client/common/platform.js +24 -0
  8. package/client/components/ai/agent-tool-call-card.jsx +10 -2
  9. package/client/components/ai/agent.js +4 -1
  10. package/client/components/ai/ai-attachments.js +87 -0
  11. package/client/components/ai/ai-chat-empty.jsx +43 -0
  12. package/client/components/ai/ai-chat-entry.jsx +13 -4
  13. package/client/components/ai/ai-chat-history-item.jsx +28 -4
  14. package/client/components/ai/ai-chat-history.jsx +2 -1
  15. package/client/components/ai/ai-chat.jsx +104 -13
  16. package/client/components/ai/ai-config-props.js +4 -130
  17. package/client/components/ai/ai-config.jsx +135 -15
  18. package/client/components/ai/ai-presets.js +173 -0
  19. package/client/components/ai/ai.styl +83 -0
  20. package/client/components/bg/css-overwrite.jsx +11 -0
  21. package/client/components/bookmark-form/bookmark-schema.js +4 -0
  22. package/client/components/bookmark-form/common/fields.jsx +3 -0
  23. package/client/components/bookmark-form/config/common-fields.js +12 -0
  24. package/client/components/bookmark-form/config/local.js +3 -2
  25. package/client/components/bookmark-form/config/serial.js +3 -2
  26. package/client/components/bookmark-form/config/ssh.js +2 -1
  27. package/client/components/bookmark-form/config/telnet.js +3 -2
  28. package/client/components/bookmark-form/index.jsx +10 -8
  29. package/client/components/common/item-filter.jsx +76 -0
  30. package/client/components/common/item-filter.styl +54 -0
  31. package/client/components/common/lazy-boundary.jsx +34 -0
  32. package/client/components/common/opacity.jsx +3 -1
  33. package/client/components/footer/footer-entry.jsx +35 -5
  34. package/client/components/footer/footer.styl +8 -1
  35. package/client/components/layout/layout.jsx +23 -31
  36. package/client/components/layout/pixed.js +3 -0
  37. package/client/components/main/main.jsx +80 -28
  38. package/client/components/main/term-fullscreen.styl +9 -3
  39. package/client/components/quick-commands/qm.styl +3 -2
  40. package/client/components/rdp/file-transfer.js +4 -4
  41. package/client/components/remote-monitor/monitor-details.jsx +458 -0
  42. package/client/components/remote-monitor/monitor-details.styl +87 -0
  43. package/client/components/remote-monitor/monitor-model.js +764 -0
  44. package/client/components/remote-monitor/remote-monitor-bar-entry.jsx +18 -0
  45. package/client/components/remote-monitor/remote-monitor-bar.jsx +344 -0
  46. package/client/components/remote-monitor/remote-monitor-bar.styl +106 -0
  47. package/client/components/remote-monitor/session-monitor.js +361 -0
  48. package/client/components/remote-monitor/use-monitor-details.js +10 -0
  49. package/client/components/remote-monitor/visibility.js +18 -0
  50. package/client/components/session/session-control.jsx +29 -2
  51. package/client/components/session/session.jsx +40 -18
  52. package/client/components/session/sessions.jsx +5 -2
  53. package/client/components/setting-panel/col.jsx +32 -6
  54. package/client/components/setting-panel/list.styl +12 -0
  55. package/client/components/setting-panel/setting-common.jsx +25 -56
  56. package/client/components/setting-panel/setting-mobile-breadcrumb.jsx +29 -0
  57. package/client/components/setting-panel/setting-modal.jsx +64 -44
  58. package/client/components/setting-panel/setting-terminal.jsx +7 -2
  59. package/client/components/setting-panel/setting-wrap.jsx +0 -3
  60. package/client/components/setting-panel/setting-wrap.styl +80 -11
  61. package/client/components/setting-panel/setting.styl +1 -1
  62. package/client/components/setting-panel/tab-triggers.jsx +71 -0
  63. package/client/components/sftp/file-compare-modal.jsx +6 -3
  64. package/client/components/sftp/file-item.jsx +5 -3
  65. package/client/components/sftp/owner-list.js +11 -2
  66. package/client/components/side-panel-r/side-panel-r.jsx +2 -2
  67. package/client/components/sidebar/index.jsx +28 -21
  68. package/client/components/sidebar/left-sidebar-icons.jsx +1 -1
  69. package/client/components/sidebar/sidebar.styl +16 -0
  70. package/client/components/sys-menu/menu-btn.jsx +30 -1
  71. package/client/components/tabs/index.jsx +2 -2
  72. package/client/components/tabs/tab-title.jsx +3 -2
  73. package/client/components/tabs/tab.jsx +5 -1
  74. package/client/components/tabs/tabs.styl +4 -0
  75. package/client/components/terminal/attach-addon-custom.js +295 -49
  76. package/client/components/terminal/automation/index.js +64 -0
  77. package/client/components/terminal/automation/keys.js +49 -0
  78. package/client/components/terminal/automation/stream-matcher.js +82 -0
  79. package/client/components/terminal/automation/strip-ansi.js +19 -0
  80. package/client/components/terminal/automation/trigger-engine.js +233 -0
  81. package/client/components/terminal/automation/trigger-presets.js +110 -0
  82. package/client/components/terminal/command-tracker-addon.js +31 -1
  83. package/client/components/terminal/mixins/index.js +27 -0
  84. package/client/components/terminal/mixins/term-attach.js +123 -0
  85. package/client/components/terminal/mixins/term-config.jsx +84 -0
  86. package/client/components/terminal/mixins/term-content.js +88 -0
  87. package/client/components/terminal/mixins/term-context-menu.jsx +291 -0
  88. package/client/components/terminal/mixins/term-file-drop.js +149 -0
  89. package/client/components/terminal/mixins/term-init.js +122 -0
  90. package/client/components/terminal/mixins/term-log.jsx +96 -0
  91. package/client/components/terminal/mixins/term-resize.js +87 -0
  92. package/client/components/terminal/mixins/term-socket.js +433 -0
  93. package/client/components/terminal/mixins/term-suggestions.js +224 -0
  94. package/client/components/terminal/mixins/term-theme.js +190 -0
  95. package/client/components/terminal/mixins/term-touch.js +136 -0
  96. package/client/components/terminal/shell-detect.js +37 -0
  97. package/client/components/terminal/shell.js +0 -28
  98. package/client/components/terminal/shortcut-bar-entry.jsx +32 -27
  99. package/client/components/terminal/shortcut-bar.jsx +4 -6
  100. package/client/components/terminal/shortcut-bar.styl +4 -0
  101. package/client/components/terminal/ssh-reload-state.js +56 -0
  102. package/client/components/terminal/startup-queue.js +379 -0
  103. package/client/components/terminal/terminal-interactive.jsx +32 -0
  104. package/client/components/terminal/terminal.jsx +102 -2007
  105. package/client/components/terminal/transfer-client-base.js +5 -29
  106. package/client/components/terminal/trzsz-client.js +1 -3
  107. package/client/components/terminal/xmodem-client.js +1 -3
  108. package/client/components/terminal/xterm-loader.js +7 -0
  109. package/client/components/terminal/zmodem-client.js +1 -3
  110. package/client/components/terminal-info/base.jsx +18 -70
  111. package/client/components/terminal-info/terminal-info-entry.jsx +13 -5
  112. package/client/components/terminal-info/terminal-info.jsx +50 -59
  113. package/client/components/terminal-info/terminal-info.styl +6 -49
  114. package/client/components/text-editor/open-text-editor.js +30 -0
  115. package/client/components/text-editor/text-editor-entry.jsx +17 -6
  116. package/client/components/text-editor/text-editor.jsx +14 -0
  117. package/client/components/theme/theme-form.jsx +22 -0
  118. package/client/components/tree-list/bookmark-transport.jsx +7 -31
  119. package/client/components/tree-list/tree-list.styl +13 -0
  120. package/client/components/triggers/trigger-editor.jsx +246 -0
  121. package/client/components/triggers/trigger-form.jsx +200 -0
  122. package/client/components/triggers/trigger-session-modal.jsx +199 -0
  123. package/client/components/triggers/trigger-setting-list.jsx +89 -0
  124. package/client/components/triggers/trigger-transport.jsx +60 -0
  125. package/client/components/triggers/triggers-field.jsx +19 -0
  126. package/client/components/widgets/widgets-list.jsx +11 -1
  127. package/client/css/mobile.styl +9 -1
  128. package/client/store/common.js +12 -1
  129. package/client/store/init-state.js +14 -0
  130. package/client/store/mcp-handler.js +158 -30
  131. package/client/store/setting.js +20 -0
  132. package/client/store/sidebar.js +12 -0
  133. package/client/store/store.js +2 -0
  134. package/client/store/sync.js +45 -9
  135. package/client/store/system-menu.js +2 -0
  136. package/client/store/tab.js +41 -3
  137. package/client/store/trigger.js +118 -0
  138. package/client/store/watch.js +13 -5
  139. package/client/views/index.pug +3 -0
  140. package/package.json +1 -1
  141. package/client/components/terminal-info/activity.jsx +0 -57
  142. package/client/components/terminal-info/data-cols-parser.jsx +0 -54
  143. package/client/components/terminal-info/disk.jsx +0 -45
  144. package/client/components/terminal-info/format-disks.js +0 -45
  145. package/client/components/terminal-info/network.jsx +0 -121
  146. package/client/components/terminal-info/resource.jsx +0 -99
  147. package/client/components/terminal-info/run-cmd.jsx +0 -263
  148. package/client/components/terminal-info/sys-info.jsx +0 -56
  149. package/client/components/terminal-info/up.jsx +0 -17
package/README.md CHANGED
@@ -1,31 +1,265 @@
1
1
  <h1 align="center" style="padding-top: 60px;padding-bottom: 40px;">
2
- <a href="https://electerm.github.io/electerm">
2
+ <a href="https://electerm.org">
3
3
  <img src="https://github.com/electerm/electerm-resource/raw/master/static/images/electerm.png", alt="" />
4
4
  </a>
5
5
  </h1>
6
6
 
7
- # electerm [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Open%20sourced%20terminal%2Fssh%2Fsftp%20client(linux%2C%20mac%2C%20win)&url=https%3A%2F%2Fgithub.com%2Felecterm%2Felecterm&hashtags=electerm,ssh,terminal,sftp)
8
-
9
- [![GitHub version](https://img.shields.io/github/release/electerm/electerm/all.svg)](https://github.com/electerm/electerm/releases)
7
+ [![GitHub version](https://badgers.space/github/release/electerm/electerm?corner_radius=m)](https://github.com/electerm/electerm/releases)
10
8
  [![Build Status](https://github.com/electerm/electerm/actions/workflows/mac-test-1.yml/badge.svg)](https://github.com/electerm/electerm/actions)
11
- [![license](https://img.shields.io/github/license/electerm/electerm.svg)](https://github.com/electerm/electerm/blob/master/LICENSE)
12
- [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
13
- [![Get it from the Snap Store](https://img.shields.io/badge/Snap-Store-green)](https://snapcraft.io/electerm)
14
- [![Get it from the Microsoft Store](https://img.shields.io/badge/Microsoft-Store-blue)](https://www.microsoft.com/store/apps/9NCN7272GTFF)
9
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/electerm/electerm/blob/master/LICENSE)
15
10
  [![GitHub Sponsors](https://img.shields.io/github/sponsors/electerm?label=Sponsors)](https://github.com/sponsors/electerm)
11
+ [![star](https://atomgit.com/electerm/electerm/star/badge.svg)](https://atomgit.com/electerm/electerm)
12
+
13
+ [English](README.md) | [中文](build/docs/README_cn.md) | [日本語](build/docs/README_jp.md)
14
+
15
+ This is react components pack for electerm sub projects
16
+
17
+ Open-sourced terminal/ssh/sftp/telnet/serialport/RDP/VNC/Spice/ftp client(Linux, Mac, Windows, Android, HarmonyOS, iOS).
18
+
19
+ Besides mainstream Windows/macOS/Linux/Android, electerm also supports HarmonyOS, iOS, and older systems — Ubuntu 18, Windows 7, macOS 10+, and special Chinese Linux distributions such as UOS, Kylin, and LoongArch (both old-world and new-world).
20
+
21
+ <p>
22
+ <a href="https://electerm.org">Homepage / Downloads</a> ·
23
+ <a href="https://theme.electerm.org">Theme</a> ·
24
+ <a href="https://github.com/electerm/electerm-web-docker">Docker</a> ·
25
+ <a href="https://demo.electerm.org">Online demo</a> ·
26
+ <a href="https://github.com/electerm/electerm-android">Android</a> ·
27
+ <a href="https://github.com/electerm/electerm-harmony">HarmonyOS</a> ·
28
+ <a href="https://apps.apple.com/cn/app/electerm/id6792971552">Apple App Store</a> ·
29
+ <a href="https://appgallery.huawei.com/app/detail?id=org.electerm.electerm">Huawei AppGallery</a> ·
30
+ <a href="https://www.microsoft.com/store/apps/9NCN7272GTFF">Microsoft Store</a> ·
31
+ <a href="https://snapcraft.io/electerm">Snap Store</a> ·
32
+ <a href="https://repos.electerm.org/deb">deb repo</a> ·
33
+ <a href="https://repos.electerm.org/rpm">rpm repo</a>
34
+ </p>
35
+
36
+ <div>🌐 <strong><a href="https://cloud.electerm.org">electerm online</a></strong> — Public free online electerm app</div>
37
+ <div>🤖 <strong><a href="https://ai.electerm.org">electerm AI</a></strong> — Free AI for electerm users</div>
38
+ <div>💻 <strong><a href="https://github.com/electerm/electerm-web">electerm-web</a></strong> — Web app version running in browser (including mobile device)</div>
39
+
40
+ ## Sponsors
41
+
42
+ <div align="center">
43
+ <a href="https://www.atlascloud.ai/?ref=PCAEL2&utm_source=github&utm_medium=link&utm_campaign=electerm">
44
+ <img src="https://github.com/electerm/electerm-resource/blob/master/static/images/atlas-cloud.png?raw=true" alt="Atlas Cloud" height="200" />
45
+ </a>
46
+ </div>
47
+
48
+ [Atlas Cloud](https://www.atlascloud.ai/?ref=PCAEL2&utm_source=github&utm_medium=link&utm_campaign=electerm) provides OpenAI-compatible AI APIs and model access for AI-powered workflows in electerm.
49
+
50
+ ----
51
+
52
+ <div align="center">
53
+ <br />
54
+ <br />
55
+ <a href="https://go.apimart.ai/gh-electerm">
56
+ <img src="https://github.com/electerm/electerm-resource/blob/master/static/images/apimart.jpg?raw=true" alt="ApiMart" width="200" />
57
+ </a>
58
+ <br />
59
+ <br />
60
+ </div>
61
+
62
+ Thanks to APIMart for sponsoring electerm! APIMart is a low-cost API platform for AI image & video generation — GPT-Image-2 from $0.006/image, 160+ images per dollar. One async API covers both image and video: submit a task, get an ID, fetch results via polling or callback. Batch tens of thousands of images without timeouts, switch models without changing code. Pay-as-you-go with no monthly fee — [sign up here to get started](https://go.apimart.ai/gh-electerm).
63
+
64
+ ----
65
+
66
+ <div align="center">
67
+ <a href="https://www.apismart.ai">
68
+ <img src="https://github.com/electerm/electerm-resource/blob/master/static/images/apismart400x400.png?raw=true" alt="ApiSmart" width="200" />
69
+ </a>
70
+ </div>
71
+
72
+ [ApiSmart](https://www.apismart.ai) provides unified access to leading AI models through a single API. Use one API key to connect with LLM, image, and video models through an OpenAI-compatible interface, without managing multiple providers separately. Switch models easily, simplify billing, and improve reliability with intelligent routing and automatic failover. Build and scale AI applications faster with one streamlined API platform.
73
+
74
+ ----
75
+
76
+ <div align="center">
77
+
78
+ <a href="https://www.digitalocean.com/?refcode=c10bcb28b846&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge"><img align="middle" src="https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%202.svg" alt="DigitalOcean Referral Badge" /></a>&nbsp;&nbsp;&nbsp;<a href="https://oss-directory.vercel.app"><img align="middle" src="https://github.com/electerm/electerm-resource/blob/master/static/images/vercel-oss-2005.png?raw=true" alt="Vercel OSS Program" /></a>
79
+
80
+ </div>
81
+
82
+ <div align="center">
83
+ <img src="https://github.com/electerm/electerm-resource/raw/master/static/images/electerm-banner-1.jpg", alt="" />
84
+ </div>
85
+
86
+ ## Features
87
+
88
+ - Works as a terminal/file manager, ssh/sftp/ftp/telnet/serialport/RDP/VNC/Spice client
89
+ - Support Window 7+(X64/ARM64), HarmonyOS,Android, iOS, Mac OS 10.15+(x64/arm64), Linux(x64/arm64/Loong64 new world & old world), even old Linux with glibc 2.17+ like UOS/Kylin/Ubuntu 18.04 etc
90
+ - Global hotkey to toggle window visibility (similar to guake, default is `ctrl + 2`)
91
+ - 🇺🇸 🇨🇳 🇧🇷 🇷🇺 🇪🇸 🇫🇷 🇹🇷 🇭🇰 🇯🇵 🇸🇦 🇩🇪 🇰🇷 🇮🇩 🇵🇱 Multi-language support([electerm-locales](https://github.com/electerm/electerm-locales), contributions/fixes welcome)
92
+ - Double click to directly edit (small) remote files.
93
+ - All kind of auth methods: publicKey, password, ssh agent, certificates, otp, netbird etc.
94
+ - Support Zmodem(rz, sz), and [Trzsz](https://github.com/trzsz/trzsz)(trz/tsz).
95
+ - Support ssh related features: tunnel, connection hopping.
96
+ - Customizable UI: themes, background image, transparent window(Mac, win).
97
+ - Global/session proxy.
98
+ - Quick commands/triggers to do predefined tasks and automattic operations
99
+ - Sync data including bookmarks to github/gitee secret gist/webdav/custom server/electerm cloud
100
+ - Quick input/mirror input to one or all terminals.
101
+ - AI assistant integration (supporting multiple LLM API formats — OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages) to help with command suggestions, script writing, and explaining selected terminal content, create bookmarks/themes, and agent mode to directly do terminal operations
102
+ - MCP (Model Context Protocol) widget for AI assistants and external tools integration - see [MCP Widget Usage Guide](https://github.com/electerm/electerm/wiki/MCP-Widget-Usage-Guide)
103
+ - Deep link support: Open connections with URLs like `telnet://192.168.2.31:34554` or `ssh://user@host:22` - see [Deep link support wiki](https://github.com/electerm/electerm/wiki/Deep-link-support)
104
+ - Command line usage: check [wiki](https://github.com/electerm/electerm/wiki/Command-line-usage)
105
+
106
+ ## Install
107
+
108
+ - For Mac user: `brew install --cask electerm`
109
+ - With snap: `sudo snap install electerm --classic`
110
+ - For some Linux distribution, you can find it from OS default App store(Ubuntu, Deepin, Mint...).
111
+ - For some linux OS, the `rpm`, `deb`, or `snap` release may not work, you can try the `tar.gz` or `.appImage` release.
112
+ - For Windows users, you can install it from [windows store](https://www.microsoft.com/store/apps/9NCN7272GTFF), command-line installer [winget](https://github.com/microsoft/winget-cli) and [scoop](https://github.com/lukesampson/scoop) is also recommended:
113
+
114
+ ```powershell
115
+ # winget https://github.com/microsoft/winget-cli
116
+ winget install electerm.electerm
117
+
118
+ # scoop https://github.com/lukesampson/scoop
119
+ scoop bucket add dorado https://github.com/chawyehsu/dorado
120
+ scoop install dorado/electerm
121
+ ```
122
+
123
+ - Install from Debian repository (for Debian/Ubuntu-based systems) with `apt` command
124
+
125
+ Check [https://repos.electerm.org/deb](https://repos.electerm.org/deb)
126
+
127
+ - Install from npm
128
+
129
+ ```bash
130
+ npm i -g electerm
131
+
132
+ ```
133
+
134
+ ## Upgrade
135
+
136
+ - Auto upgrade: When a new version is released, you will get an upgrade notification after you start electerm again. You can then click the upgrade button to upgrade.
137
+ - Download: Just download the latest edition, reinstall.
138
+ - Npm: If you install from npm, just run `npm i -g electerm` again.
139
+ - If use Snap or some other distribution system, these systems may provide upgrades.
140
+
141
+ ## Known issues
142
+
143
+ [https://github.com/electerm/electerm/wiki/Know-issues](https://github.com/electerm/electerm/wiki/Know-issues)
16
144
 
17
- Open-sourced terminal/ssh/telnet/serialport/sftp client(linux, mac, win).
145
+ ## Troubleshoot
18
146
 
19
- This is react components src for electerm
147
+ [https://github.com/electerm/electerm/wiki/Troubleshoot](https://github.com/electerm/electerm/wiki/Troubleshoot)
20
148
 
21
- ## Use
149
+ ## Discussion
22
150
 
23
- todo
151
+ [![Discord](https://img.shields.io/badge/Discord-Join-blue?logo=discord)](https://discord.gg/855W7g8EVd)
152
+
153
+ [Discussion board](https://github.com/electerm/electerm/discussions)
154
+
155
+ ![electerm-wechat-group-qr.jpg](https://electerm.org/electerm-wechat-group-qr.jpg)
156
+
157
+ ## Support
158
+
159
+ Would love to hear from you, please tell me what you think, [submit an issue](https://github.com/electerm/electerm/issues), [Start a new discussion](https://github.com/electerm/electerm/discussions/new), [create/fix language files](https://github.com/electerm/electerm-locales) or create pull requests, all welcome.
160
+
161
+ ## Sponsor this project
162
+
163
+ github sponsor
164
+
165
+ [https://github.com/sponsors/electerm](https://github.com/sponsors/electerm)
166
+
167
+ kofi
168
+
169
+ [https://ko-fi.com/zhaoxudong](https://ko-fi.com/zhaoxudong)
170
+
171
+ wechat donate
172
+
173
+ [![wechat donate](https://electerm.org/electerm-wechat-donate.png)](https://github.com/electerm)
174
+
175
+ TRON TRN20
176
+
177
+ [![TRN20 donate](https://github.com/electerm/electerm-resource/blob/master/static/images/trn20.png?raw=true)]
178
+
179
+ Address: TXk3pQNmQu1vihH76RaEFnK9wg13x4LLCZ
180
+
181
+ ## Dev
182
+
183
+ ```bash
184
+ # May only works in Linux
185
+ # needs nodejs/npm, suggest using nvm to install nodejs/npm
186
+ # with nodejs 24.x
187
+
188
+ git clone git@github.com:electerm/electerm.git
189
+ cd electerm
190
+ npm config set legacy-peer-deps true
191
+ npm i
192
+
193
+ # start vite dev server, requires port 5570
194
+ npm start
195
+
196
+ # in a separate terminal session run app
197
+ npm run app
198
+
199
+ # code format check
200
+ npm run lint
201
+
202
+ # code format fix
203
+ npm run fix
204
+ ```
205
+
206
+ ## Test
207
+
208
+ ```bash
209
+ npm run b
210
+ npm run prepare-test
211
+ cp ./build/.sample.env ./.env
212
+
213
+ # edit .env, fill your test host/username/password, may only works in mac OS
214
+ npm run test
215
+ ```
216
+
217
+ ## Test build
218
+
219
+ ```bash
220
+ # May only works in Linux
221
+ # Install yarn first(to do yarn autoclean)
222
+ # See https://yarnpkg.com/en/docs/install
223
+
224
+ # Build linux only with -l
225
+ npm i
226
+ npm run b
227
+ npm run pb
228
+ ./node_modules/.bin/electron-builder --linux tar.gz
229
+ # or replace tar.gz to rpm/deb/AppImage
230
+ # check dist/ folder
231
+
232
+ # build for linux arm/
233
+ ./node_modules/.bin/electron-builder --linux --arm64
234
+ ```
235
+
236
+ ## Video guide
237
+
238
+ - [https://electerm.org/videos](https://electerm.org/videos)
24
239
 
25
240
  ## Change log
26
241
 
27
242
  Visit [Releases](https://github.com/electerm/electerm/releases).
28
243
 
244
+ ## Contact author
245
+
246
+ [zxdong@gmail.com](mailto:zxdong@gmail.com)
247
+
248
+
29
249
  ## License
30
250
 
31
251
  MIT
252
+
253
+ ## Star History
254
+
255
+ <p>
256
+ <a href="https://www.star-history.com/electerm/electerm"><img src="https://api.star-history.com/badge?repo=electerm/electerm" alt="Star History Rank" /></a>
257
+ </p>
258
+
259
+ <a href="https://www.star-history.com/?repos=electerm%2Felecterm&type=date&legend=top-left">
260
+ <picture>
261
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=electerm/electerm&type=date&legend=top-left&sealed_token=DvPlttPaLtq6RPIWRANYX08-8ZJyrJalhombrkDcg1IwWOMPMIplgi85q0FiwrbhE3lRIi_yxvOWdell731CGQvzlfJMt2Sa6VfCvQ80BwEtQ6RpPchEiw" />
262
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=electerm/electerm&type=date&legend=top-left&sealed_token=DvPlttPaLtq6RPIWRANYX08-8ZJyrJalhombrkDcg1IwWOMPMIplgi85q0FiwrbhE3lRIi_yxvOWdell731CGQvzlfJMt2Sa6VfCvQ80BwEtQ6RpPchEiw" />
263
+ <img alt="Star History Chart" src="https://api.star-history.com/chart?repos=electerm/electerm&type=date&legend=top-left&sealed_token=DvPlttPaLtq6RPIWRANYX08-8ZJyrJalhombrkDcg1IwWOMPMIplgi85q0FiwrbhE3lRIi_yxvOWdell731CGQvzlfJMt2Sa6VfCvQ80BwEtQ6RpPchEiw" />
264
+ </picture>
265
+ </a>
@@ -1,11 +1,27 @@
1
+ import { getItem, setItem } from './safe-local-storage.js'
2
+
1
3
  const {
2
4
  openDialog
3
5
  } = window.api
4
6
 
5
- export async function chooseSaveDirectory (opts) {
7
+ export const lastSaveFolderKey = 'last-save-folder'
8
+
9
+ /**
10
+ * Open a folder select dialog, remembers last selected folder in
11
+ * localStorage and uses it as next dialog's defaultPath.
12
+ * Pass `defaultPath` to override the remembered one.
13
+ * @param {Object} opts extra openDialog options
14
+ * @returns {Promise<string|undefined>} selected folder path
15
+ */
16
+ export async function chooseSaveDirectory (opts = {}) {
17
+ const {
18
+ defaultPath,
19
+ ...rest
20
+ } = opts
6
21
  const savePaths = await openDialog({
7
22
  title: 'Choose a folder to save file(s)',
8
23
  message: 'Choose a folder to save file(s)',
24
+ defaultPath: defaultPath || getItem(lastSaveFolderKey) || undefined,
9
25
  properties: [
10
26
  'openDirectory',
11
27
  'showHiddenFiles',
@@ -14,10 +30,13 @@ export async function chooseSaveDirectory (opts) {
14
30
  'treatPackageAsDirectory',
15
31
  'dontAddToRecent'
16
32
  ],
17
- ...opts
33
+ ...rest
18
34
  })
19
35
  if (!savePaths || !savePaths.length) {
20
36
  return undefined
21
37
  }
38
+ if (savePaths[0]) {
39
+ setItem(lastSaveFolderKey, savePaths[0])
40
+ }
22
41
  return savePaths[0]
23
42
  }
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * constants
3
3
  */
4
+ import { isMacJs } from './platform.js'
4
5
  import logoPath1Ref from '@electerm/electerm-resource/res/imgs/electerm-round-128x128.png'
5
6
  import logoPath2Ref from '@electerm/electerm-resource/res/imgs/electerm.png'
6
7
  import logoPath3Ref from '@electerm/electerm-resource/res/imgs/electerm-watermark.png'
@@ -29,6 +30,7 @@ export const termControlHeight = 32
29
30
  export const maxDragMove = 30
30
31
  export const splitDraggerWidth = 5
31
32
  export const minTerminalWidth = 90
33
+ export const minTerminalFontSize = 5
32
34
  export const filePropMinWidth = 1
33
35
  export const contextMenuHeight = 28
34
36
  export const contextMenuWidth = 280
@@ -78,12 +80,11 @@ export const authTypeMap = buildConst([
78
80
  ])
79
81
 
80
82
  export const footerHeight = 36
83
+ export const remoteMonitorBarHeight = 28
81
84
  export const quickCommandBoxHeight = 180
82
85
  export const shortcutBarHeight = 44
83
86
  export const shortcutBarLsKey = 'shortcut-bar-buttons'
84
- export const isWin = typeof window.et.isWin === 'undefined' ? window.pre.isWin : window.et.isWin
85
- export const isMac = typeof window.et.isMac === 'undefined' ? window.pre.isMac : window.et.isMac
86
- export const isMacJs = /Macintosh|Mac|Mac OS|MacIntel|MacPPC|Mac68K/gi.test(window.navigator.userAgent)
87
+ export { isWin, isMac, isMacJs } from './platform.js'
87
88
  export const ctrlOrCmd = isMacJs ? 'cmd' : 'ctrl'
88
89
  export const typeMap = buildConst([
89
90
  'remote',
@@ -106,13 +107,15 @@ export const settingMap = buildConst([
106
107
  'addressBookmarks',
107
108
  'profiles',
108
109
  'widgets',
109
- 'workspaces'
110
+ 'workspaces',
111
+ 'triggers'
110
112
  ])
111
113
 
112
114
  export const staticNewItemTabs = new Set([
113
115
  'terminalThemes',
114
116
  'quickCommands',
115
- 'profiles'
117
+ 'profiles',
118
+ 'triggers'
116
119
  ])
117
120
 
118
121
  export const infoTabs = buildConst([
@@ -201,6 +204,9 @@ export const commonLineEndings = commonTxLineEndings
201
204
  export const maxBatchInput = 30
202
205
  export const windowControlWidth = 94
203
206
  export const mobileBreakpoint = 600
207
+ // breakpoint matching the setting panel's `@media (max-width: 800px)` CSS —
208
+ // must be kept in sync with setting-wrap.styl
209
+ export const settingPanelMobileBreakpoint = 800
204
210
  export const baseUpdateCheckUrls = [
205
211
  packInfo.homepage,
206
212
  'https://gitee.com/github-zxdong262/electerm/raw/gh-pages'
@@ -235,6 +241,16 @@ export const settingShortcutsId = 'setting-shortcuts'
235
241
  export const settingAiId = 'setting-ai'
236
242
  export const settingCommonId = 'setting-common'
237
243
  export const settingPasswordsId = 'setting-passwords'
244
+ // settings that only apply to the desktop (electron) app,
245
+ // hidden when window.et.isWebApp is true
246
+ export const webAppHiddenSettings = [
247
+ 'hotkey',
248
+ 'opacity',
249
+ 'useSystemTitleBar',
250
+ 'checkUpdateOnStart',
251
+ 'allowMultiInstance',
252
+ 'disableDeveloperTool'
253
+ ]
238
254
  export const defaultEnvLang = 'en_US.UTF-8'
239
255
  export const fileActions = {
240
256
  cancel: 'cancel',
@@ -361,7 +377,8 @@ export const syncDataMaps = {
361
377
  quickCommands: ['quickCommands'],
362
378
  profiles: ['profiles'],
363
379
  addressBookmarks: ['addressBookmarks'],
364
- workspaces: ['workspaces']
380
+ workspaces: ['workspaces'],
381
+ triggers: ['triggers']
365
382
  }
366
383
  export const terminalTypes = [
367
384
  'xterm-256color',
@@ -42,6 +42,12 @@ export default function createTitle (res, hide = true) {
42
42
  ) {
43
43
  f = `[T]${f}`
44
44
  }
45
+ if (res.mcpStatus) {
46
+ f = `[${res.mcpStatus}]${f}`
47
+ }
48
+ if (res.from === 'mcp') {
49
+ f = `[mcp]${f}`
50
+ }
45
51
  if (type && type !== 'ssh') {
46
52
  f = `[${type}]${f}`
47
53
  }
@@ -58,6 +58,18 @@ export default {
58
58
  'network',
59
59
  'disks'
60
60
  ],
61
+ remoteMonitorBarEnabled: false,
62
+ remoteMonitorBarItems: [
63
+ 'hostname',
64
+ 'cpu',
65
+ 'cpuHistory',
66
+ 'memory',
67
+ 'upload',
68
+ 'download',
69
+ 'uptime',
70
+ 'users',
71
+ 'disks'
72
+ ],
61
73
  filePropsEnabled: [
62
74
  'name',
63
75
  'size',
@@ -75,11 +87,13 @@ export default {
75
87
  sshSftpSplitView: false,
76
88
  showCmdSuggestions: false,
77
89
  autoReconnectTerminal: false,
90
+ restoreTerminalSessionOnReload: false,
78
91
  startDirectoryLocal: '',
79
92
  allowMultiInstance: false,
80
93
  disableDeveloperTool: false,
81
94
  dragDropBehavior: 'ask',
82
95
  switchTabOnHover: false,
96
+ disableTabIndex: false,
83
97
  disableShortcutBar: false,
84
98
  leftSideBarIcons: [
85
99
  'newBookmark',
@@ -26,6 +26,11 @@ export default (arr, tab) => {
26
26
  id: '',
27
27
  name: e(newQuickCommand)
28
28
  }
29
+ } else if (tab === settingMap.triggers) {
30
+ return {
31
+ id: '',
32
+ name: e(settingMap.triggers)
33
+ }
29
34
  } else if (tab === settingMap.profiles) {
30
35
  return {
31
36
  id: '',
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Platform flags.
3
+ *
4
+ * Split out of constants.js: that module imports PNG assets at the top level,
5
+ * which makes anything importing it unloadable in a plain Node (unit test)
6
+ * context. Modules that only need isWin/isMac should import from here.
7
+ */
8
+ const read = (name) => {
9
+ if (typeof window === 'undefined') {
10
+ return false
11
+ }
12
+ const { et, pre } = window
13
+ if (et && typeof et[name] !== 'undefined') {
14
+ return et[name]
15
+ }
16
+ return pre ? !!pre[name] : false
17
+ }
18
+
19
+ export const isWin = read('isWin')
20
+
21
+ export const isMac = read('isMac')
22
+
23
+ export const isMacJs = typeof navigator !== 'undefined' &&
24
+ /Macintosh|Mac|Mac OS|MacIntel|MacPPC|Mac68K/gi.test(navigator.userAgent)
@@ -1,4 +1,4 @@
1
- import { useState } from 'react'
1
+ import { useState, useEffect } from 'react'
2
2
  import { Tag } from 'antd'
3
3
  import {
4
4
  CaretDownOutlined,
@@ -33,11 +33,19 @@ function formatResult (result) {
33
33
  }
34
34
  }
35
35
 
36
- export default function AgentToolCallCard ({ toolCall }) {
36
+ export default function AgentToolCallCard ({ toolCall, autoCollapse }) {
37
37
  const [expanded, setExpanded] = useState(toolCall.status === 'running')
38
38
  const { name, args, status, result } = toolCall
39
39
  const Icon = toolIcons[name] || CodeOutlined
40
40
 
41
+ // Collapse every tool call once the agent session is done,
42
+ // user can still expand them again by clicking the header
43
+ useEffect(() => {
44
+ if (autoCollapse) {
45
+ setExpanded(false)
46
+ }
47
+ }, [autoCollapse])
48
+
41
49
  function renderStatus () {
42
50
  if (status === 'running') {
43
51
  return <LoadingOutlined className='agent-tool-status-running' />
@@ -60,7 +60,10 @@ export async function runAgentLoop (chatEntry, config, abortRef, setIsStreaming,
60
60
  } else {
61
61
  messages = [
62
62
  { role: 'system', content: buildAgentSystemPrompt(config) },
63
- { role: 'user', content: chatEntry.prompt }
63
+ {
64
+ role: 'user',
65
+ content: chatEntry.promptWithAttachments || chatEntry.prompt
66
+ }
64
67
  ]
65
68
  }
66
69
  const toolCallsLog = []
@@ -0,0 +1,87 @@
1
+ // text file attachment support for AI chat
2
+ // only text files are supported: content is read and inlined
3
+ // into the prompt, images/binaries are rejected
4
+ import uid from '../../common/uid'
5
+
6
+ export const MAX_ATTACHMENT_FILE_SIZE = 50 * 1024
7
+ export const MAX_ATTACHMENT_TOTAL_SIZE = 100 * 1024
8
+
9
+ const BINARY_SNIFF_LEN = 8 * 1024
10
+ const decoder = new TextDecoder('utf-8')
11
+
12
+ // binary check: null byte anywhere, or too many control chars
13
+ function looksLikeText (buf) {
14
+ const len = Math.min(buf.byteLength, BINARY_SNIFF_LEN)
15
+ if (!len) {
16
+ return false
17
+ }
18
+ const arr = new Uint8Array(buf, 0, len)
19
+ let control = 0
20
+ for (const b of arr) {
21
+ if (b === 0) {
22
+ return false
23
+ }
24
+ if (b < 9 || (b > 13 && b < 32)) {
25
+ control++
26
+ }
27
+ }
28
+ return control / len <= 0.1
29
+ }
30
+
31
+ // trailing U+FFFD means a multi-byte char got cut at the size boundary
32
+ function stripTrailingBadChars (str) {
33
+ let end = str.length
34
+ while (end > 0 && str[end - 1] === '\uFFFD') {
35
+ end--
36
+ }
37
+ return str.slice(0, end)
38
+ }
39
+
40
+ export async function readTextAttachment (file) {
41
+ const buf = await file.slice(0, MAX_ATTACHMENT_FILE_SIZE).arrayBuffer()
42
+ if (!looksLikeText(buf)) {
43
+ return {
44
+ error: 'notTextFile'
45
+ }
46
+ }
47
+ const truncated = file.size > MAX_ATTACHMENT_FILE_SIZE
48
+ let content = stripTrailingBadChars(decoder.decode(buf))
49
+ if (truncated) {
50
+ content += '\n...[truncated]'
51
+ }
52
+ return {
53
+ attachment: {
54
+ id: uid(),
55
+ name: file.name,
56
+ size: file.size,
57
+ truncated,
58
+ content
59
+ }
60
+ }
61
+ }
62
+
63
+ export function validateAttachmentTotal (list, extraSize = 0) {
64
+ const total = list.reduce((s, a) => s + a.size, 0) + extraSize
65
+ return total <= MAX_ATTACHMENT_TOTAL_SIZE
66
+ }
67
+
68
+ export function formatSize (n) {
69
+ if (n < 1024) {
70
+ return n + ' B'
71
+ }
72
+ if (n < 1024 * 1024) {
73
+ return (n / 1024).toFixed(1) + ' KB'
74
+ }
75
+ return (n / 1024 / 1024).toFixed(1) + ' MB'
76
+ }
77
+
78
+ export function buildAttachmentsBlock (attachments) {
79
+ if (!attachments || !attachments.length) {
80
+ return ''
81
+ }
82
+ return attachments.map(a => {
83
+ const name = String(a.name).replace(/"/g, "'")
84
+ const attr = a.truncated ? ' truncated="true"' : ''
85
+ return `<file name="${name}"${attr}>\n${a.content}\n</file>`
86
+ }).join('\n\n')
87
+ }
@@ -0,0 +1,43 @@
1
+ import { logoPath3 } from '../../common/constants'
2
+ import { refsStatic } from '../common/ref'
3
+
4
+ const examples = [
5
+ 'Explain current terminal output',
6
+ 'Why did this command fail?',
7
+ 'Write a script to clean up old log files'
8
+ ]
9
+
10
+ function useExample (text) {
11
+ const inst = refsStatic.get('AIChat')
12
+ if (inst) {
13
+ inst.setPrompt(text)
14
+ }
15
+ }
16
+
17
+ export default function AiChatEmpty () {
18
+ return (
19
+ <div className='ai-chat-empty'>
20
+ <div className='ai-chat-empty-inner'>
21
+ <div
22
+ className='ai-chat-watermark'
23
+ style={{ '--ai-watermark': `url(${logoPath3})` }}
24
+ />
25
+ <div className='ai-chat-empty-title'>Ask AI about your terminal</div>
26
+ <div className='ai-chat-empty-hint'>
27
+ Explain output, debug errors, or switch to Agent to let AI run commands
28
+ </div>
29
+ <div className='ai-chat-empty-examples'>
30
+ {examples.map(t => (
31
+ <div
32
+ key={t}
33
+ className='ai-chat-empty-example'
34
+ onClick={() => useExample(t)}
35
+ >
36
+ {t}
37
+ </div>
38
+ ))}
39
+ </div>
40
+ </div>
41
+ </div>
42
+ )
43
+ }