This guide is the complete technical reference for eDEX-UI: its architecture, the terminal client/server design, the system-monitoring pipeline, security model, configuration surface, build and distribution process, and per-module internals. It is written for administrators deploying eDEX-UI (including kiosk/touchscreen scenarios), developers building from source or authoring themes and keyboard layouts, and architects who want to understand how the project works end to end.
It is the companion to the User Guide, which covers day-to-day usage. Everything here is derived directly from the eDEX-UI source at commit 04a00c4 (version 2.2.8).
1. Executive Summary
eDEX-UI is an Electron desktop application that presents a fullscreen, TRON-inspired "computer console" UI wrapping a real terminal emulator and a suite of live system monitors. It is cross-platform (Windows, macOS, Linux), single-window, single-instance, and fullscreen by default.
| Attribute | Value |
|---|---|
| Version documented | 2.2.8 |
| License | GPL-3.0 |
| Author | Gabriel "Squared" SAILLARD |
| App ID | com.edex.ui |
| Project status | Archived (October 18, 2021); no longer maintained |
| Runtime | Electron ^12.1.0 (Chromium renderer + Node.js main) |
| Terminal | xterm.js 4.14.1 (renderer) ↔ node-pty 0.10.1 (main) over a local WebSocket |
| System data | systeminformation 5.9.7, run across a worker cluster |
| Languages | JavaScript (ES6 classes), HTML, CSS |
| Source size | ~134 files, ~264 KB of source across src/ |
Architectural shape
eDEX-UI is a two-process Electron app with an unusual internal twist: the terminal is wired together with a localhost WebSocket between the renderer (xterm.js front-end) and the main process (node-pty back-end), rather than going purely through Electron IPC. The main process additionally spins up a cluster of Node worker processes to offload systeminformation polling so the UI stays smooth.
┌──────────────────────── Electron main process (Node.js) ───────────────────────┐
│ src/_boot.js │
│ • single-instance lock, settings/shortcuts/theme bootstrapping │
│ • creates the BrowserWindow (loads src/ui.html) │
│ • Terminal (role:"server") → node-pty + ws WebSocket server (:3000, :3002-5) │
│ • src/_multithread.js → cluster of N workers running systeminformation │
│ • IPC handlers: ttyspawn, theme/kb override, systeminformation-call, log │
└───────────────▲───────────────────────────────▲───────────────────────────────┘
│ Electron IPC │ WebSocket ws://127.0.0.1:<port>
│ (resize, cwd, process, si) │ (keystrokes ↔ pty output)
┌───────────────┴───────────────────────────────┴───────────────────────────────┐
│ Electron renderer process (Chromium) — src/ui.html + src/_renderer.js │
│ • boot animation → initUI() builds the layout │
│ • 18 module classes in src/classes/ (Terminal client, Keyboard, FS, monitors) │
│ • window.si Proxy → IPC → main-process worker cluster │
└────────────────────────────────────────────────────────────────────────────────┘
Note
Because the project is archived, this guide also calls out which subsystems are known to be fragile (GeoIP lookup, proxy handling, Windows CWD tracking) so operators know what to expect rather than discovering it in production.
2. System Architecture
2.1 Process model
| Process | Source | Responsibilities |
|---|---|---|
| Main | src/_boot.js |
App lifecycle, window creation, terminal back-end(s), config bootstrapping, IPC routing |
| Renderer | src/ui.html + src/_renderer.js |
UI construction, all 18 visual modules, terminal front-end, input handling |
| Multithread controller + workers | src/_multithread.js |
A Node cluster master plus N workers that execute systeminformation calls |
2.2 Startup sequence
The boot flow in src/_boot.js (app.on('ready', …)) proceeds:
- Single-instance lock via
app.requestSingleInstanceLock(). A second launch logs "Another instance of eDEX is already running" and exits. - GPU tuning — appends Chromium switches
ignore-gpu-blocklist,enable-gpu-rasterization,enable-video-decodeto trade some stability for rendering performance (notably on Linux). - Proxy env scrubbing —
http_proxy/https_proxyare deleted from the environment to avoid breaking the internal WebSocket connections (issue #222). - Config bootstrapping — creates the user-data directory and writes default
settings.json,shortcuts.json, andlastWindowState.jsonif absent; mirrors the built-inthemes/,keyboards/, andfonts/into the user-data directory (overwriting each launch). - Version history — appends the current version + timestamp to
versions_log.json. - Shell resolution — resolves the configured
shellto an absolute path withwhich. Failure here stalls startup at "Settings loaded!". - Environment assembly — loads a clean login shell environment via
shell-env, then overlaysTERM=xterm-256color,COLORTERM=truecolor,TERM_PROGRAM=eDEX-UI,TERM_PROGRAM_VERSION, plus any userenv. - Terminal back-end — instantiates
Terminal({role:"server", …})onsettings.port(default3000). - Multithread controller —
require("./_multithread.js")forks the worker cluster. - Window creation —
createWindow(settings)builds theBrowserWindowand loadsui.html. - Extra-tab back-ends — reserves four extra TTY slots on ports
basePort+2 … basePort+5for additional tabs.
2.3 The terminal: a WebSocket-bridged client/server
The single most important design element lives in src/classes/terminal.class.js, which is one class with two roles:
Server role (main process)
node-pty spawn(shell, args, {cols, rows, cwd, env})
│
├── ws WebSocket server on settings.port (verifyClient: max 1 client)
│ ws "message" → tty.write(msg) (keystrokes in)
│ tty.onData → ws.send(data) (pty output out)
│
└── 1-second tick: CWD tracking + foreground-process tracking
Linux : readlink /proc/<pid>/cwd ; ps -o comm ... -g <pid>
macOS : lsof -a -d cwd -p <pid> ; ps -o comm ... -g <pid>
Windows: unsupported → "Fallback cwd" (detached mode)
node-ptyspawns the actual shell. Non-Windows shells get--loginby default when noshellArgsare set.- A
wsWebSocket server is created on the port.verifyClientrejects a second connection, so each pty has exactly one front-end. - Keystrokes arrive as WebSocket messages and are written to the pty; pty output is sent back over the socket.
- Every second the server updates the current working directory and the foreground process name and pushes them to the renderer over the Electron IPC channel
terminal_channel-<port>.
Client role (renderer)
- Builds an
xterm.jsTerminalwith theFitAddon,WebglAddon,LigaturesAddon, andAttachAddon. - Opens
new WebSocket("ws://127.0.0.1:<port>"); theAttachAddonbinds the socket to xterm so output renders and input is sent. - Resize is negotiated over IPC (
terminal_channel-<port>→"Resize"), recomputed byFitAddon.proposeDimensions()with aspect-ratio correction heuristics. - Receives
"New cwd","Fallback cwd", and"New process"IPC messages — the CWD drives the filesystem panel; the process name drives the tab label.
Important
The WebSocket server binds to the loopback interface and accepts only one client per port, but it performs no authentication. Any local process able to reach
127.0.0.1:<port>before the renderer connects could occupy the socket. On a single-user desktop this is low-risk; on shared/multi-user hosts treat the terminal ports as a local trust boundary. See Security.
2.4 Multi-tab terminals
initUI() creates the main terminal on settings.port. Up to four additional tabs are supported (five total). When a user opens an empty tab, the renderer sends an ttyspawn IPC; the main process allocates the next free port from the reserved pool (basePort+2 … basePort+5), spawns a new Terminal server in the active tab's current working directory, and replies with ttyspawn-reply: SUCCESS: <port>. If the pool is exhausted it replies ERROR: max number of ttys reached.
2.5 The systeminformation pipeline (window.si)
System data is the heaviest workload, so it is offloaded from the renderer:
renderer: window.si.cpu() (a Proxy)
│ ipc.send("systeminformation-call", "cpu", id, ...args)
▼
main (_multithread.js master):
• dispatch round-robin to a worker (or call inline if args.length>1)
▼
worker: si["cpu"](...).then(res => process.send({id, res}))
▲
│ ipc "systeminformation-reply-<id>"
renderer: Promise resolves with res
window.siin the renderer is a JavaScriptProxy. Any property access (window.si.cpu,window.si.mem, …) returns a function that round-trips through IPC and resolves a Promise.- The master (
_multithread.js) forksmin(os.cpus().length - 1, 7)workers (leaving a core for the renderer; capped at 7 per issue #904). - Calls are dispatched round-robin to workers; multi-argument calls are executed inline by the master.
- An illegal method name (
si[type]undefined) is rejected with a warning, preventing arbitrary function invocation through the channel.
2.6 Rendering and UI construction
src/_renderer.js orchestrates the front-end:
- Disables
eval()globally (window.eval/global.evalthrow) as a hardening measure. - Defines HTML/CSS sanitization helpers (
_escapeHtml,_purifyCSS,_encodePathURI). - Loads
settings.json,shortcuts.json,lastWindowState.jsonand applies CLI overrides (--nointro,--nocursor). - Loads the theme (
_loadTheme) — injects CSS variables, fonts, and any theme-definedinjectCSS(purified). - Runs the boot animation (unless
nointro) readingassets/misc/boot_log.txt. initUI()builds the DOM scaffold and instantiates every module in order (see Module Reference).- Registers global keyboard shortcuts via
electron.remote.globalShortcut, re-registering on window focus and clearing on blur.
3. Repository Structure
edex-ui/
├── package.json Root: build config (electron-builder), dev deps, scripts
├── src/
│ ├── _boot.js Main process entry (package.json "main")
│ ├── _renderer.js Renderer orchestration
│ ├── _multithread.js systeminformation worker cluster
│ ├── ui.html Renderer HTML shell
│ ├── package.json Runtime deps (xterm, node-pty, ws, systeminformation, …)
│ ├── classes/ 18 ES6 module classes (see §7)
│ └── assets/
│ ├── css/ Per-module stylesheets (mod_*.css, main.css, boot_screen.css)
│ ├── themes/ 20 built-in theme JSON files
│ ├── kb_layouts/ 19 keyboard layout JSON files
│ ├── fonts/ Fira Code/Mono, United Sans (woff2)
│ ├── audio/ 13 sound-effect WAV files
│ ├── icons/ file-icons.json (generated SVG icon set)
│ ├── misc/ boot_log.txt, file-icons-match.js, grid.json
│ └── vendor/ encom-globe.js (3-D globe library)
├── file-icons/ Git submodules: icon source sets (atom, devopicons, etc.)
├── file-icons-generator.js Regenerates file-icons.json + matcher from submodules
├── prebuild-minify.js CI minification of src before packaging
├── media/ App icons + screenshots
├── SECURITY.md
└── LICENSE GPL-3.0
Key file roles
| File | Role |
|---|---|
src/_boot.js |
Main process: lifecycle, window, terminal server, config defaults |
src/_renderer.js |
Renderer: UI build, settings/shortcuts editors, theme loader, shortcut registration |
src/_multithread.js |
cluster master + workers for systeminformation |
src/classes/terminal.class.js |
Dual-role terminal (xterm client / node-pty+ws server) |
file-icons-generator.js |
Build helper: compiles SVG icon submodules into file-icons.json and a matchIcon() function |
prebuild-minify.js |
Pre-package minification step |
4. Requirements
4.1 Runtime (release binaries)
| Requirement | Detail |
|---|---|
| OS | Windows (x64/ia32), macOS (x64), Linux (x64/arm64) |
| Node.js | Not required for release builds — Electron is bundled |
| GPU | Hardware acceleration recommended; GPU blocklist is bypassed for performance |
| Network | Optional, but required for the network-status, globe, and update-check features |
| Permissions | Read access to /proc (Linux) and lsof/ps availability (macOS) for CWD/process tracking |
4.2 Build-from-source
| Requirement | Detail |
|---|---|
| Node.js + npm | Required to install dependencies and rebuild native modules |
| Native build tools | node-gyp and a C/C++ toolchain (for node-pty) |
| Windows | windows-build-tools + Python 2.7 (legacy native build path); run shell as administrator |
| macOS | Xcode Command Line Tools |
electron-rebuild |
Rebuilds node-pty against the bundled Electron ABI |
4.3 Runtime dependencies (src/package.json)
| Package | Version | Purpose |
|---|---|---|
@electron/remote |
^1.2.2 |
Renderer access to main-process modules (app, clipboard, globalShortcut, …) |
xterm + addons (-attach, -fit, -ligatures, -webgl) |
4.14.1 / various |
Terminal front-end and rendering |
node-pty |
0.10.1 |
Pseudo-terminal back-end (native module) |
ws |
7.5.5 |
WebSocket server bridging pty ↔ xterm |
systeminformation |
5.9.7 |
All CPU/RAM/network/process/hardware data |
geolite2-redist + maxmind |
^2.0.4 / 4.3.2 |
GeoIP database download + lookups for the globe |
smoothie |
1.35.0 |
Real-time streaming charts (CPU, network) |
howler |
2.2.3 |
Sound-effect playback |
pdfjs-dist |
2.11.338 |
In-app PDF viewer |
color |
3.2.1 |
Theme color filters / terminal palette generation |
nanoid |
3.1.30 |
Modal and request IDs |
mime-types |
^2.1.33 |
File-type detection in the browser |
pretty-bytes |
5.6.0 |
Human-readable byte formatting |
shell-env |
3.0.1 |
Capturing a clean login-shell environment |
signale |
1.4.0 |
Main-process logging |
tail, which, username |
various | Misc utilities |
osx-temperature-sensor |
1.0.7 (optional) |
macOS CPU temperature |
5. Security Model
eDEX-UI follows the permissive Electron security posture that was common before the contextBridge hardening era, because the renderer needs broad Node.js access to run terminals, read the filesystem, and call native modules. This is a deliberate design trade-off, not an oversight — but administrators deploying it (especially on shared or kiosk machines) should understand it precisely.
5.1 BrowserWindow webPreferences (from src/_boot.js)
| Option | Value | Implication |
|---|---|---|
nodeIntegration |
true |
The renderer can require() Node modules directly |
contextIsolation |
false |
Page scripts and Electron/Node share one context |
enableRemoteModule |
true |
@electron/remote exposes main-process objects to the renderer |
webSecurity |
true |
Same-origin policy stays enforced |
allowRunningInsecureContent |
false |
Mixed/insecure content blocked |
nodeIntegrationInSubFrames |
false |
Subframes do not get Node access |
experimentalFeatures |
from settings.experimentalFeatures (default false) |
Optional Chromium experimental web features (flagged DANGEROUS in-app) |
backgroundThrottling |
false |
Keeps panels updating when unfocused |
Warning
With
nodeIntegration:trueandcontextIsolation:false, any code that executes in the renderer has full local user privileges (filesystem, process spawning, network). eDEX mitigates this by only ever loading its own localfile://UI and locking navigation — but if you extend eDEX or inject untrusted CSS/HTML/themes, you are running it inside a fully privileged context.
5.2 Mitigations actually present in the code
eDEX does not rely on a sandbox; instead it constrains what can run:
| Layer | Mechanism | Source |
|---|---|---|
| No remote content | Only file://ui.html is ever loaded |
createWindow() |
| Navigation lock | will-navigate is prevented unless the URL equals the current page |
app.on('web-contents-created') |
| External links | new-window is prevented and routed to shell.openExternal |
same |
eval() disabled |
window.eval/global.eval throw "eval() is disabled for security reasons." |
_renderer.js |
| Input/CSS sanitization | _escapeHtml, _purifyCSS (strips <), _encodePathURI for filenames and theme CSS |
_renderer.js |
| Single instance | requestSingleInstanceLock() |
_boot.js |
| Single WS client | ws verifyClient rejects connection #2 per port |
terminal.class.js |
| si method allow-check | systeminformation-call rejects unknown method names |
_multithread.js |
5.3 Network egress
eDEX makes several outbound connections. There are no inbound listeners except the loopback terminal WebSockets.
| Destination | Purpose | Module |
|---|---|---|
127.0.0.1:3000 (+3002–3005) |
Terminal pty ↔ xterm bridge (loopback only) | terminal.class.js |
myexternalip.com:443 |
Discover the machine's external IPv4 | netstat.class.js |
| GeoLite2 redistribution endpoint | Download the GeoIP database to userData/geoIPcache |
netstat.class.js (via geolite2-redist) |
settings.pingAddr (default 1.1.1.1:80) |
TCP connect-time latency ("ping") | netstat.class.js |
api.github.com/repos/GitSquared/edex-ui/releases/latest |
Update check on launch | updateChecker.class.js |
Peer IPs from systeminformation.networkConnections() |
Pinned on the globe (display only) | locationGlobe.class.js |
Caution
On restricted / proxied networks these lookups fail. eDEX scrubs
http_proxy/https_proxyat startup and does not offer proxy configuration (issue #1050), so the network panels may stay blank behind a corporate proxy. This does not affect the terminal itself.
5.4 Things that do not exist (negative knowledge)
To prevent fabricated configuration assumptions:
- No HTTP/REST API. eDEX exposes nothing over HTTP; the only sockets are the loopback terminal WebSockets.
- No authentication or multi-user model. It is a single-user desktop app.
- No remote management, telemetry, or analytics. The only outbound calls are those listed in §5.3.
- No plugin system or extension API. Customization is limited to themes, keyboard layouts, settings, and shortcuts.
- No environment-variable configuration. All configuration is via JSON files in the user-data directory (and two CLI flags).
- No system-wide config file. Configuration is strictly per-user under the Electron
userDatapath.
5.5 Known security-relevant issues
| Issue | Note |
|---|---|
| #1160 | Password Mode previously revealed keystrokes on macOS — verify on your version before relying on it for secret entry |
| #1103 | unable to verify the first certificate on intercepting proxies |
| Unsigned binaries | Release artifacts are not code-signed (forceCodeSigning: false) — distribute checksums/links from the official repo only |
6. Configuration Reference
All configuration lives in the Electron user-data directory:
| Platform | Path |
|---|---|
| Windows | %APPDATA%\eDEX-UI\ |
| macOS | ~/Library/Application Support/eDEX-UI/ |
| Linux | ~/.config/eDEX-UI/ |
| File | Contents |
|---|---|
settings.json |
All behavioral settings (table below) |
shortcuts.json |
Keyboard + custom command shortcuts |
lastWindowState.json |
{ "useFullscreen": bool } |
versions_log.json |
Per-version first/last-seen timestamps |
themes/, keyboards/, fonts/ |
Mirrored copies of built-in assets + user additions |
geoIPcache/ |
Downloaded GeoLite2 database |
6.1 settings.json — complete reference
Defaults are those written by _boot.js on first run. Keys marked (editor) are exposed in the settings editor but have no hardcoded default.
| Key | Type | Default | Description |
|---|---|---|---|
shell |
string | bash / powershell.exe (Win) |
Program run as the terminal |
shellArgs |
string | "" |
Arguments passed to the shell (non-Windows defaults to --login when empty) |
cwd |
string | userData dir | Starting working directory; must exist or startup fails |
env |
object/string (editor) | — | Custom environment overrides merged into the shell env |
username |
string (editor) | — | Display name shown in the boot greeting (falls back to OS username) |
keyboard |
string | en-US |
On-screen keyboard layout code |
theme |
string | tron |
Theme name |
termFontSize |
number | 15 |
Terminal font size (px) |
audio |
bool | true |
Master sound-effects switch |
audioVolume |
number | 1.0 |
Sound-effects volume 0.0–1.0 |
disableFeedbackAudio |
bool | false |
Mute frequent stdin/stdout click sounds only |
clockHours |
number | 24 |
12 or 24-hour clock |
pingAddr |
string | 1.1.1.1 |
IPv4 address for the latency test |
port |
number | 3000 |
Base port for the terminal WebSocket(s) |
monitor |
number (editor) | primary | Display index to open on |
iface |
string (editor) | auto | Force a specific network interface for monitoring |
nointro |
bool | false |
Skip the boot animation/logo |
nocursor |
bool | false |
Hide the mouse cursor (kiosk) |
forceFullscreen |
bool | true |
Launch fullscreen |
allowWindowed |
bool | false |
Permit F11 to leave fullscreen |
keepGeometry |
bool (editor) | true |
Keep a 16:9 aspect ratio in windowed mode |
excludeThreadsFromToplist |
bool | true |
Collapse threads in the process list |
hideDotfiles |
bool | false |
Hide dotfiles in the browser |
fsListView |
bool | false |
Use list view in the browser |
experimentalGlobeFeatures |
bool | false |
Scan terminal output for IPs and pin them on the globe |
experimentalFeatures |
bool | false |
Enable Chromium experimental web features (DANGEROUS) |
Note
experimentalGlobeFeaturesmakes the terminal client scan all pty output for IPv4 addresses and pin them on the globe (issue #397). This means terminal content is parsed by a regex on every message — disable it if you process sensitive output or want lower CPU usage.
6.2 shortcuts.json — schema
An array of shortcut objects:
[
{ "type": "app", "trigger": "Ctrl+Shift+C", "action": "COPY", "enabled": true },
{ "type": "app", "trigger": "Ctrl+X", "action": "TAB_X", "enabled": true },
{ "type": "shell", "trigger": "Ctrl+Shift+Alt+Space", "action": "neofetch", "linebreak": true, "enabled": false }
]
| Field | Meaning |
|---|---|
type |
"app" (built-in action) or "shell" (run a terminal command) |
trigger |
Accelerator string (Ctrl/Alt/Shift + key); X in TAB_X expands to tabs 1–5 |
action |
One of the app actions below, or for shell type the command text to send |
linebreak |
(shell only) append \r so the command runs immediately |
enabled |
Whether the shortcut is active |
App action identifiers: COPY, PASTE, NEXT_TAB, PREVIOUS_TAB, TAB_X (TAB_1…TAB_5), SETTINGS, SHORTCUTS, FUZZY_SEARCH, FS_LIST_VIEW, FS_DOTFILES, KB_PASSMODE, DEV_DEBUG, DEV_RELOAD.
Tip
Shortcuts are registered globally via
globalShortcutwhile eDEX has focus and unregistered on blur, so they will not interfere with other applications when eDEX is in the background.
6.3 Command-line flags
eDEX accepts exactly two runtime flags (parsed in _renderer.js):
| Flag | Effect |
|---|---|
--nointro |
Skip the boot animation (the bundled npm start uses this) |
--nocursor |
Hide the mouse cursor |
There are no other CLI flags and no environment-variable configuration.
7. Module Reference
The renderer's functionality is implemented as 18 ES6 classes in src/classes/, instantiated by initUI(). Each panel manages its own DOM and its own update timer (driven by window.si calls).
7.1 Core interaction modules
| Class | File | Responsibility |
|---|---|---|
Terminal |
terminal.class.js |
Dual-role: xterm.js front-end (client) and node-pty + ws back-end (server); CWD/process tracking; resize; copy/paste; color filters |
Keyboard |
keyboard.class.js |
On-screen keyboard: renders a layout JSON, handles touch/mouse/physical key sync, modifier state, dead-key accent composition, Password Mode, and shortcut dispatch |
FilesystemDisplay |
filesystem.class.js |
CWD-following file grid; click-to-cd, Ctrl/Shift-click behaviors; disk view; special icons for eDEX config files; opens PDFs/text/media |
FuzzyFinder |
fuzzyFinder.class.js |
Modal fuzzy search over the current directory's entries |
Modal |
modal.class.js |
Draggable modal windows (error/warning/info/custom) with augmented-ui framing; backs settings, shortcuts, viewers |
7.2 System-monitor modules (left column)
| Class | File | Data source (window.si.*) / refresh |
|---|---|---|
Clock |
clock.class.js |
Local time; 1s |
Sysinfo |
sysinfo.class.js |
Date, os.uptime(), OS type, battery(); uptime 60s, battery 3s |
HardwareInspector |
hardwareInspector.class.js |
system(), chassis(); 20s |
Cpuinfo |
cpuinfo.class.js |
cpu(), currentLoad(), cpuTemperature(), processes(); per-core Smoothie charts |
RAMwatcher |
ramwatcher.class.js |
mem(); 440-point grid + swap bar; 1.5s |
Toplist |
toplist.class.js |
processes(); top 5; click → full sortable process modal; 2s |
7.3 Network modules (right column)
| Class | File | Behavior |
|---|---|---|
Netstat |
netstat.class.js |
Interface selection, online/offline, external IP via myexternalip.com, GeoIP via maxmind/geolite2-redist, TCP ping; 2s |
LocationGlobe |
locationGlobe.class.js |
ENCOM 3-D globe; pins your location + established connections (networkConnections()); optional IP scanning of terminal output |
Conninfo |
conninfo.class.js |
Up/down traffic Smoothie charts + cumulative bytes via networkStats(iface); 1s |
7.4 Media / support modules
| Class | File | Responsibility |
|---|---|---|
AudioManager |
audiofx.class.js |
Loads 13 WAV effects via howler; returns a Proxy so missing sounds no-op safely |
DocReader |
docReader.class.js |
PDF.js-based viewer (page nav, zoom) inside a modal |
MediaPlayer |
mediaPlayer.class.js |
Audio/video player controls (play/pause, seek, volume, fullscreen) |
UpdateChecker |
updateChecker.class.js |
Queries the GitHub releases API; shows a modal if a newer version exists |
Note
Several modules guard their DOM updates in
try/catchbecause the DOM can be torn down mid-update during a theme hot-swap (which reloads the UI). This is intentional defensive code, not a sign of error.
7.5 Inter-module communication
- The terminal client exposes
oncwdchange/onprocesschangecallbacks.FilesystemDisplay.followTab()subscribes tooncwdchangeto re-read the directory;_renderer.jssubscribes toonprocesschangeto update the tab label. window.modsholds the live panel instances (clock,sysinfo,netstat,globe, …) so modules can reference each other (e.g.Conninforeadswindow.mods.netstat.iface).window.term[n]holds the per-tab terminal clients;window.currentTermis the active index.
8. Build & Distribution
8.1 Running from source
Linux / macOS
git clone https://github.com/GitSquared/edex-ui.git
cd edex-ui
npm run install-linux # or rely on Xcode CLT on macOS
npm run start
install-linux runs npm install at the root and in src/, then electron-rebuild -f -w node-pty to recompile the native pty module against Electron's ABI.
Windows
Open cmd or PowerShell as administrator, then:
git clone https://github.com/GitSquared/edex-ui.git
cd edex-ui
npm run install-windows
npm run start
The legacy preinstall-windows step installs windows-build-tools, node-gyp, and points PYTHON at the bundled Python 2.7 for native compilation.
npm run start launches electron src --nointro.
8.2 npm scripts
| Script | Purpose |
|---|---|
start |
electron src --nointro |
install-linux / install-windows |
Install deps + electron-rebuild native node-pty |
preinstall-windows |
Install Windows build toolchain + Python 2.7 |
prebuild-linux / -darwin / -windows |
Copy src → prebuild-src, minify, then npm install there |
build-linux / -darwin / -windows |
Run electron-builder for the host OS |
postbuild-* |
Remove the temporary prebuild-src |
test |
Prebuild + snyk test for dependency vulnerabilities |
init-file-icons |
git submodule update --init |
update-file-icons |
Pull icon submodules + run file-icons-generator.js |
Important
Because
node-ptyis a native module, you can only build artifacts for the host OS you are on — there is no cross-compilation. Runnpm install(not theinstall-*variants) beforebuild-*.
8.3 Packaging (electron-builder)
The root package.json build block defines the release matrix:
| Platform | Target | Artifact name |
|---|---|---|
| Linux | AppImage (x64, ia32, arm64, armv7l) | eDEX-UI-Linux-${arch}.AppImage |
| macOS | dmg (x64) | eDEX-UI-macOS-${arch}.dmg |
| Windows | NSIS (x64, ia32) | eDEX-UI-Windows-${arch}.exe |
asar: true— source packed into an asar archive.forceCodeSigning: false— binaries are unsigned.npmRebuild: true— native modules rebuilt during packaging.- NSIS:
oneClick: false,allowToChangeInstallationDirectory: true,deleteAppDataOnUninstall: true. publish: github— releases are published to GitHub.
8.4 The boot pipeline
prebuild-minify.js (via terser/clean-css) minifies JS and CSS before packaging so distributed binaries are smaller and obfuscated. file-icons-generator.js compiles the SVG icon submodules (Atom file-icons, devopicons, mfixx, font-awesome, bytesize) into src/assets/icons/file-icons.json plus a generated file-icons-match.js that maps filenames to icons by regex.
9. Operations
9.1 Deploying as a kiosk / touchscreen display
eDEX-UI is well-suited to a fullscreen kiosk. Recommended configuration:
{
"forceFullscreen": true,
"allowWindowed": false,
"nocursor": true,
"nointro": true,
"theme": "tron-notype",
"audio": false
}
- [x]
forceFullscreen+allowWindowed:falselocks the display fullscreen (F11is intercepted). - [x]
nocursor:truehides the pointer for touch-only use. - [x]
nointro:trueskips the boot animation on every restart. - [x] A
-notypetheme hides the keyboard/filesystem for a cleaner monitor wall, if input isn't needed. - [x] Launch with
--nointro --nocursorto enforce kiosk behavior even before settings load. - [x] Pre-seed
settings.jsonandthemes//keyboards/in the user-data directory during provisioning.
Tip
eDEX opens on the primary display by default. Use the
monitorsetting (a display index) to target a specific screen in multi-monitor setups.
9.2 Logs and diagnostics
- The main process logs via
signaleto stdout/stderr (startup timing, terminal lifecycle, errors). Launch from a terminal to see them. - The renderer forwards errors to the main log over IPC (
ipc.send("log", "error", …)) and shows them as on-screen error modals. - Open Chromium DevTools with
Ctrl+Shift+I(enable theDEV_DEBUGshortcut first — it ships disabled).
9.3 Resetting configuration
To reset eDEX to defaults, quit it and delete (or rename) the user-data directory (§6). eDEX recreates default settings.json, shortcuts.json, and re-mirrors built-in assets on next launch.
9.4 Performance tuning
| Lever | Effect |
|---|---|
| Theme choice | -notype/simpler themes and disabling color filters reduce GPU load |
experimentalGlobeFeatures: false |
Stops per-message IP regex scanning of terminal output |
| Fewer tabs | Each tab is a full pty + WebSocket + tracking timer |
| Worker cap | The si worker count is min(cores-1, 7) — already bounded |
backgroundThrottling |
Disabled by design (keeps panels live); not user-tunable |
10. Troubleshooting (Operator Reference)
In-code error strings and their meaning:
Error: eDEX-UI crashed
An uncaught exception reached the main process. The dialog shows the underlying message; eDEX closes all ptys and exits with code 1. Launch from a terminal to capture the signale.fatal stack trace.
Error: Another instance of eDEX is already running. Cannot proceed.
The single-instance lock rejected a second launch. Use the existing window or fully quit it first.
Error: Configured cwd path does not exist.
settings.cwd points to a missing directory. Fix settings.json and restart.
Stuck at "Settings loaded!"
which(settings.shell) failed to resolve the shell to a path (issue #1168). Ensure the configured shell is installed and on PATH.
Error: ERROR: max number of ttys reached
All five terminal slots are occupied. Close a tab (exit its shell) before opening another.
Error: eval() is disabled for security reasons.
Expected — eval is intentionally disabled. If you see this it means some code (often an injected theme/plugin attempt) tried to call eval. Remove the offending customization.
Error: RAM Watcher Error: Bad memory values
systeminformation.mem() returned inconsistent totals on this platform. Usually transient; if persistent, it indicates a systeminformation incompatibility with the OS.
Error: fsDisp media displayer: unknown type <…>
The filesystem display tried to render a media type it doesn't handle. Open the file externally (Ctrl+click) instead.
Globe / IP blank, NetStat: Error parsing data from myexternalip.com
The external-IP lookup failed (offline, blocked, or proxied) (issues #964, #1135). The terminal is unaffected.
unable to verify the first certificate
TLS interception (corporate proxy). eDEX has no proxy support (issue #1050); network panels stay blank.
High CPU usage
Continuous graphs + globe + polling (issue #1169). Apply the performance levers in §9.4.
Layout overlap on ultrawide displays
Unusual aspect ratios are not fully supported (issues #832, #1162). Use a 16:9 display or extra_ratios CSS.
11. Code Quality & Conventions
| Aspect | Observation |
|---|---|
| Style | Plain ES6 classes, one per file under src/classes/, each module.exports-ing its class. No transpilation or bundler; files are loaded directly by the Electron renderer. |
| State | Heavily uses globals on window (window.mods, window.term, window.settings, window.modals). Acceptable for a single-window app but tightly couples modules. |
| DOM construction | Modules build DOM via template-literal innerHTML. User/file input is routed through _escapeHtml / _encodePathURI; theme CSS through _purifyCSS. |
| Concurrency guards | Update methods use currentlyUpdating/_reading flags to prevent overlapping async refreshes (e.g. RAMwatcher, Cpuinfo, FilesystemDisplay). |
| Error resilience | DOM updates wrapped in try/catch to survive theme hot-swaps; the AudioManager Proxy and window.si Proxy degrade gracefully. |
| Platform branching | Many process.platform === "win32" branches (CWD tracking, CPU temp, paths) — Windows is a consistent special case. |
| Native dependency | node-pty requires electron-rebuild; the single biggest build/portability constraint. |
12. Potential Improvements
Note
The project is archived, so these are observations for forks or maintainers rather than a roadmap.
- Migrate to the modern Electron security model. Move to
contextIsolation:true+ acontextBridgepreload exposing a minimal API, and run the terminal bridge over IPC instead of an unauthenticated localhost WebSocket. This is a substantial rewrite but removes the broadest part of the attack surface. - Replace the deprecated external-IP/GeoIP path. The
myexternalip.comdependency and GeoLite2 download are common failure points; a configurable provider (or making the feature optional/offline) would improve reliability on restricted networks. - Add proxy support. Honoring
http_proxy/https_proxy(or an explicit proxy setting) would fix the corporate-network failures (#1050, #1103) instead of scrubbing the variables. - Windows CWD tracking. Investigate a Windows-native mechanism (e.g. querying the pty child's working directory via the Win32 API) to remove the "detached" limitation.
- Reduce idle CPU. Throttle or pause graphs/globe when unfocused (currently
backgroundThrottling:false), and make polling intervals configurable. - Decouple modules from globals. Introduce a small event bus or dependency injection to reduce the
window.*coupling and ease testing. - Pin/refresh dependencies.
node-pty 0.10,xterm 4, and Electron 12 are several major versions behind current; upgrading would bring security and rendering improvements (at the cost of API migration).
13. Quick Reference
Default ports
| Port | Use |
|---|---|
3000 |
Main terminal WebSocket |
3002–3005 |
Extra terminal tabs (up to 4) |
Default keyboard shortcuts
| Trigger | Action |
|---|---|
Ctrl+Shift+C / Ctrl+Shift+V |
Copy / paste |
Ctrl+Tab / Ctrl+Shift+Tab |
Next / previous tab |
Ctrl+X+n |
Switch to / create tab n |
Ctrl+Shift+S / Ctrl+Shift+K |
Settings / shortcuts editor |
Ctrl+Shift+F |
Fuzzy file search |
Ctrl+Shift+L / Ctrl+Shift+H |
List view / dotfiles toggle |
Ctrl+Shift+P |
Password Mode |
Ctrl+Shift+I / Ctrl+Shift+F5 |
DevTools / reload |
Config directory
| Platform | Path |
|---|---|
| Windows | %APPDATA%\eDEX-UI\ |
| macOS | ~/Library/Application Support/eDEX-UI/ |
| Linux | ~/.config/eDEX-UI/ |
Build commands
npm run install-linux # or install-windows (admin)
npm run start # run from source
npm install && npm run build-linux # package for host OS (build-darwin / build-windows)
Key facts
| Fact | Value |
|---|---|
| Entry point | src/_boot.js |
| Main IPC channels | terminal_channel-<port>, systeminformation-call, ttyspawn, log, *ThemeOverride, *KbOverride |
| Max terminal tabs | 5 |
| Scrollback | 1,500 lines |
| si worker count | min(cores − 1, 7) |
| Built-in themes / layouts | 20 / 19 |
| License | GPL-3.0 |