@electerm/electerm-react 5.3.26 → 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.
- package/README.md +246 -12
- package/client/common/choose-save-folder.js +21 -2
- package/client/common/constants.js +20 -6
- package/client/common/create-title.jsx +6 -0
- package/client/common/default-setting.js +14 -0
- package/client/common/init-setting-item.js +5 -0
- package/client/common/platform.js +24 -0
- package/client/components/ai/agent-tool-call-card.jsx +10 -2
- package/client/components/ai/agent.js +4 -1
- package/client/components/ai/ai-attachments.js +87 -0
- package/client/components/ai/ai-chat-empty.jsx +43 -0
- package/client/components/ai/ai-chat-entry.jsx +13 -4
- package/client/components/ai/ai-chat-history-item.jsx +28 -4
- package/client/components/ai/ai-chat-history.jsx +2 -1
- package/client/components/ai/ai-chat.jsx +104 -13
- package/client/components/ai/ai-config-props.js +4 -130
- package/client/components/ai/ai-config.jsx +135 -15
- package/client/components/ai/ai-presets.js +173 -0
- package/client/components/ai/ai.styl +83 -0
- package/client/components/bg/css-overwrite.jsx +11 -0
- package/client/components/bookmark-form/bookmark-schema.js +4 -0
- package/client/components/bookmark-form/common/fields.jsx +3 -0
- package/client/components/bookmark-form/config/common-fields.js +12 -0
- package/client/components/bookmark-form/config/local.js +3 -2
- package/client/components/bookmark-form/config/serial.js +3 -2
- package/client/components/bookmark-form/config/ssh.js +2 -1
- package/client/components/bookmark-form/config/telnet.js +3 -2
- package/client/components/common/item-filter.jsx +76 -0
- package/client/components/common/item-filter.styl +54 -0
- package/client/components/common/lazy-boundary.jsx +34 -0
- package/client/components/common/opacity.jsx +3 -1
- package/client/components/footer/footer-entry.jsx +35 -5
- package/client/components/footer/footer.styl +8 -1
- package/client/components/layout/layout.jsx +23 -31
- package/client/components/layout/pixed.js +3 -0
- package/client/components/main/main.jsx +55 -28
- package/client/components/main/term-fullscreen.styl +9 -3
- package/client/components/quick-commands/qm.styl +3 -2
- package/client/components/rdp/file-transfer.js +4 -4
- package/client/components/remote-monitor/monitor-details.jsx +458 -0
- package/client/components/remote-monitor/monitor-details.styl +87 -0
- package/client/components/remote-monitor/monitor-model.js +764 -0
- package/client/components/remote-monitor/remote-monitor-bar-entry.jsx +18 -0
- package/client/components/remote-monitor/remote-monitor-bar.jsx +344 -0
- package/client/components/remote-monitor/remote-monitor-bar.styl +106 -0
- package/client/components/remote-monitor/session-monitor.js +361 -0
- package/client/components/remote-monitor/use-monitor-details.js +10 -0
- package/client/components/remote-monitor/visibility.js +18 -0
- package/client/components/session/session-control.jsx +29 -2
- package/client/components/session/session.jsx +40 -18
- package/client/components/session/sessions.jsx +5 -2
- package/client/components/setting-panel/setting-common.jsx +25 -56
- package/client/components/setting-panel/setting-modal.jsx +57 -42
- package/client/components/setting-panel/setting-terminal.jsx +7 -2
- package/client/components/setting-panel/setting.styl +1 -1
- package/client/components/setting-panel/tab-triggers.jsx +71 -0
- package/client/components/sftp/file-compare-modal.jsx +6 -3
- package/client/components/sftp/file-item.jsx +5 -3
- package/client/components/sftp/owner-list.js +11 -2
- package/client/components/side-panel-r/side-panel-r.jsx +2 -2
- package/client/components/sys-menu/menu-btn.jsx +30 -1
- package/client/components/tabs/index.jsx +2 -2
- package/client/components/tabs/tab-title.jsx +3 -2
- package/client/components/tabs/tab.jsx +5 -1
- package/client/components/terminal/attach-addon-custom.js +295 -49
- package/client/components/terminal/automation/index.js +64 -0
- package/client/components/terminal/automation/keys.js +49 -0
- package/client/components/terminal/automation/stream-matcher.js +82 -0
- package/client/components/terminal/automation/strip-ansi.js +19 -0
- package/client/components/terminal/automation/trigger-engine.js +233 -0
- package/client/components/terminal/automation/trigger-presets.js +110 -0
- package/client/components/terminal/command-tracker-addon.js +31 -1
- package/client/components/terminal/mixins/index.js +27 -0
- package/client/components/terminal/mixins/term-attach.js +123 -0
- package/client/components/terminal/mixins/term-config.jsx +84 -0
- package/client/components/terminal/mixins/term-content.js +88 -0
- package/client/components/terminal/mixins/term-context-menu.jsx +291 -0
- package/client/components/terminal/mixins/term-file-drop.js +149 -0
- package/client/components/terminal/mixins/term-init.js +122 -0
- package/client/components/terminal/mixins/term-log.jsx +96 -0
- package/client/components/terminal/mixins/term-resize.js +87 -0
- package/client/components/terminal/mixins/term-socket.js +433 -0
- package/client/components/terminal/mixins/term-suggestions.js +224 -0
- package/client/components/terminal/mixins/term-theme.js +190 -0
- package/client/components/terminal/mixins/term-touch.js +136 -0
- package/client/components/terminal/shell-detect.js +37 -0
- package/client/components/terminal/shell.js +0 -28
- package/client/components/terminal/shortcut-bar-entry.jsx +6 -3
- package/client/components/terminal/shortcut-bar.jsx +4 -6
- package/client/components/terminal/shortcut-bar.styl +4 -0
- package/client/components/terminal/ssh-reload-state.js +56 -0
- package/client/components/terminal/startup-queue.js +379 -0
- package/client/components/terminal/terminal-interactive.jsx +32 -0
- package/client/components/terminal/terminal.jsx +102 -2007
- package/client/components/terminal/transfer-client-base.js +5 -29
- package/client/components/terminal/trzsz-client.js +1 -3
- package/client/components/terminal/xmodem-client.js +1 -3
- package/client/components/terminal/xterm-loader.js +7 -0
- package/client/components/terminal/zmodem-client.js +1 -3
- package/client/components/terminal-info/base.jsx +18 -70
- package/client/components/terminal-info/terminal-info-entry.jsx +13 -5
- package/client/components/terminal-info/terminal-info.jsx +50 -59
- package/client/components/terminal-info/terminal-info.styl +6 -49
- package/client/components/text-editor/open-text-editor.js +30 -0
- package/client/components/text-editor/text-editor-entry.jsx +17 -6
- package/client/components/text-editor/text-editor.jsx +14 -0
- package/client/components/triggers/trigger-editor.jsx +246 -0
- package/client/components/triggers/trigger-form.jsx +200 -0
- package/client/components/triggers/trigger-session-modal.jsx +199 -0
- package/client/components/triggers/trigger-setting-list.jsx +89 -0
- package/client/components/triggers/trigger-transport.jsx +60 -0
- package/client/components/triggers/triggers-field.jsx +19 -0
- package/client/components/widgets/widgets-list.jsx +11 -1
- package/client/css/mobile.styl +9 -1
- package/client/store/common.js +12 -1
- package/client/store/init-state.js +7 -0
- package/client/store/mcp-handler.js +158 -30
- package/client/store/setting.js +9 -0
- package/client/store/store.js +2 -0
- package/client/store/sync.js +2 -0
- package/client/store/tab.js +41 -3
- package/client/store/trigger.js +118 -0
- package/client/store/watch.js +13 -5
- package/client/views/index.pug +3 -0
- package/package.json +1 -1
- package/client/components/terminal-info/activity.jsx +0 -57
- package/client/components/terminal-info/data-cols-parser.jsx +0 -54
- package/client/components/terminal-info/disk.jsx +0 -45
- package/client/components/terminal-info/format-disks.js +0 -45
- package/client/components/terminal-info/network.jsx +0 -121
- package/client/components/terminal-info/resource.jsx +0 -99
- package/client/components/terminal-info/run-cmd.jsx +0 -263
- package/client/components/terminal-info/sys-info.jsx +0 -56
- 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.
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
[](https://github.com/electerm/electerm/releases)
|
|
7
|
+
[](https://github.com/electerm/electerm/releases)
|
|
10
8
|
[](https://github.com/electerm/electerm/actions)
|
|
11
|
-
[](https://standardjs.com)
|
|
13
|
-
[](https://snapcraft.io/electerm)
|
|
14
|
-
[](https://www.microsoft.com/store/apps/9NCN7272GTFF)
|
|
9
|
+
[](https://github.com/electerm/electerm/blob/master/LICENSE)
|
|
15
10
|
[](https://github.com/sponsors/electerm)
|
|
11
|
+
[](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> <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
|
-
|
|
145
|
+
## Troubleshoot
|
|
18
146
|
|
|
19
|
-
|
|
147
|
+
[https://github.com/electerm/electerm/wiki/Troubleshoot](https://github.com/electerm/electerm/wiki/Troubleshoot)
|
|
20
148
|
|
|
21
|
-
##
|
|
149
|
+
## Discussion
|
|
22
150
|
|
|
23
|
-
|
|
151
|
+
[](https://discord.gg/855W7g8EVd)
|
|
152
|
+
|
|
153
|
+
[Discussion board](https://github.com/electerm/electerm/discussions)
|
|
154
|
+
|
|
155
|
+

|
|
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
|
+
[](https://github.com/electerm)
|
|
174
|
+
|
|
175
|
+
TRON TRN20
|
|
176
|
+
|
|
177
|
+
[]
|
|
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
|
|
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
|
-
...
|
|
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
|
|
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([
|
|
@@ -238,6 +241,16 @@ export const settingShortcutsId = 'setting-shortcuts'
|
|
|
238
241
|
export const settingAiId = 'setting-ai'
|
|
239
242
|
export const settingCommonId = 'setting-common'
|
|
240
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
|
+
]
|
|
241
254
|
export const defaultEnvLang = 'en_US.UTF-8'
|
|
242
255
|
export const fileActions = {
|
|
243
256
|
cancel: 'cancel',
|
|
@@ -364,7 +377,8 @@ export const syncDataMaps = {
|
|
|
364
377
|
quickCommands: ['quickCommands'],
|
|
365
378
|
profiles: ['profiles'],
|
|
366
379
|
addressBookmarks: ['addressBookmarks'],
|
|
367
|
-
workspaces: ['workspaces']
|
|
380
|
+
workspaces: ['workspaces'],
|
|
381
|
+
triggers: ['triggers']
|
|
368
382
|
}
|
|
369
383
|
export const terminalTypes = [
|
|
370
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',
|
|
@@ -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
|
-
{
|
|
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
|
+
}
|