Skip to content

emaxe/eTty

Repository files navigation

eTty

🇷🇺 Русский

Modern terminal emulator built with Electron. Lightweight, fast, and feature-rich.

eTty icon

Features

Terminal

  • Multiple tabs with independent zsh sessions
  • WebGL-accelerated rendering (canvas fallback)
  • Kitty keyboard protocol — Shift+Enter, Ctrl+Enter, Ctrl+Shift+Enter sequences
  • Full Unicode support — Cyrillic, accented characters, emoji
  • Shell directory tracking via OSC 7 — file tree syncs automatically
  • Command busy indicator via OSC 133 — navigation buttons reflect shell state
  • Tab drag-and-drop — reorder tabs by dragging the grip handle
  • Configurable new tab placement — choose whether new tabs open adjacent to the active tab or at the end; hold Cmd/Ctrl while clicking "+" to toggle the behavior (configurable in Settings)
  • Auto-open tab for busy terminal — triggering a run-script or cd from the file tree while the active tab is occupied by an agent automatically opens a new tab for the command
  • 2,500 lines scrollback buffer (performance-optimized)
  • Scroll-to-bottom button — floating button appears when you scroll up into history; click to jump back to the latest output

Command History

  • Shared global history (5,000 lines) across all tabs
  • Per-tab history files — each tab gets its own HISTFILE
  • Smart merging — new commands merge back to global on tab close
  • Session restore — history survives app restarts
  • Automatic cleanup of orphaned history files

File Tree (Sidebar)

  • Lazy-loaded directory tree with expand/collapse
  • Hidden files toggle
  • Quick navigationcd .. and cd ~ buttons
  • Live sync — filesystem watcher with 500ms debounce
  • Context menus — new file/folder, rename, delete, copy, paste, open external, copy relative path
  • Hover overlay — quick-action buttons appear on hover: cd into directory, copy path, and run script (▶) to execute the file in the active terminal
  • Multi-select — Ctrl/Cmd+Click, Shift+Click range, Ctrl+A select all
  • Bulk operations — copy (Ctrl+C / Cmd+C), paste (Ctrl+V / Cmd+V), and delete (Delete) on the current selection
  • Drag-and-drop — move files/folders within the tree
  • Undo — Ctrl+Z to undo last move operation
  • Binary file handling — images, videos, executables (.dmg, .exe, etc.) open with the OS default application instead of the code editor
  • Resizable sidebar (150–600px)
  • Path traversal protection — all paths validated against CWD

Code Editor

  • CodeMirror 6 with syntax highlighting for 20+ languages: JavaScript/TypeScript, Python, Go, Rust, HTML, CSS/SCSS, JSON, YAML, Markdown, Vue, C#
  • Send to terminal — select code and send it to the active shell (Cmd+Enter)
  • Unsaved changes indicator
  • Auto-features — bracket closing, fold gutter, active line highlight, search
  • Resizable editor panel

Git Integration

  • Status bar showing ± +N -N diff stats, updated every 5 seconds
    • Click on stats to toggle Git panel
  • Branch management — switch, create, delete branches
  • Inline diff viewer with colored additions/deletions
  • Commit, push, discard — all from the GUI
  • Per-file stats — additions and deletions count for each changed file

Git Diff Highlighting

  • File tree indicators — new files (green), modified (blue), deleted (red + strikethrough)
  • Folder dot markers — nested changes bubble up to parent directories (deleted > modified > new)
  • Editor gutter bars — 3px color strips left of line numbers for added (green) and modified (blue) lines
  • Auto-refresh — polling every 5 seconds + immediate update on file save (Cmd+S)
  • Repository-aware — only active when the working directory is inside a git repo

Project Search

  • Modal search dialogCmd+F (macOS) / Ctrl+F (Windows/Linux), or double-tap Shift
  • File names + contents — searches both simultaneously; file-name matches shown first
  • Search options — case sensitive, whole word, regex toggles; include/exclude glob patterns
  • Live preview — click a result to preview file contents with highlighted matches
  • Quick open — double-click or Enter opens the file in the editor and closes the dialog
  • Cancellable — long searches abort automatically when the query changes

AI Agents

  • Status-bar launcher — one-click launch of detected CLI agents
  • Auto-detection — Claude, Codex, Copilot, Cursor Agent, OpenCode, Qwen, Agento
  • Busy lock — agent buttons disabled while terminal is busy
  • Active agent highlight — launched agent button glows while running
  • Force-disable — toggle agents on/off in Settings
  • Proxy support — configure HTTP proxy for all agent commands
  • Customizable quick replies — define agent-specific quick commands (e.g., /clear, Ok, Продолжай) via Settings; drag-and-drop to reorder
  • Double-click to select active agent — when the terminal is busy but the active agent wasn't auto-detected (e.g., launched manually or via another app), double-click any agent button in the status bar to manually assign it as active. This enables that agent's quick-reply buttons.
  • Per-agent Shift+Enter mode — configure how Shift+Enter behaves for each AI agent (Kitty protocol, newline, or Ctrl+J). Qwen and Agento default to Ctrl+J mode; others default to Kitty protocol.

Settings

  • 7 built-in themes: Catppuccin Mocha (default), Monokai, Dracula, One Dark, Nord, Solarized Dark, Gruvbox Dark
  • Focus indicator — glow, border, top-line, or none
  • File tree behavior — collapse children on close, single/double-click to open
  • Prompt style — default (from ~/.zshrc), short, minimal, arrow (for new tabs)
  • Status bar size — compact, standard, or large; adjustable in Settings → Appearance
  • New tab placementmodifierAdjacent (Cmd/Ctrl opens next to active tab) or modifierEnd (Cmd/Ctrl appends to end); configurable in Settings → Terminal
  • AI agent quick replies — CRUD editor with per-agent toggles; drag-and-drop reordering
  • Auto-persisted to disk with debounced saves

Session Persistence

  • Tab state saved on quit, restored on next launch (with confirmation dialog)
  • Per-tab tree state — expanded directories and scroll position remembered when switching tabs
  • Menu option to manually restore tabs

Keyboard Shortcuts

Shortcut Action
Cmd+F / Ctrl+F Open project search dialog
Cmd+E / Ctrl+E Toggle editor panel
Cmd+S / Ctrl+S Save file in editor
Cmd+Enter Send selection from editor to terminal
Shift+Enter Kitty protocol: \x1b[13;2u
Ctrl+Enter Kitty protocol: \x1b[13;5u
Ctrl+Shift+Enter Kitty protocol: \x1b[13;6u
Cmd+ArrowLeft (macOS) Home — \x1b[H
Cmd+ArrowRight (macOS) End — \x1b[F

Tech Stack

Component Technology
Desktop shell Electron 33
Build tooling electron-vite (Vite-based)
Terminal UI xterm.js 5.5 + WebGL, Fit, WebLinks, Search addons
PTY backend node-pty 1.0 (native module)
Code editor CodeMirror 6 with 13 language packages (JS/TS, Python, Go, Rust, HTML, CSS, JSON, YAML, Markdown, Vue, C#)
Git operations simple-git
UI font Roboto (global application font)
Packaging electron-builder
Logging electron-log
Auto-update electron-updater (stub)

Getting Started

Prerequisites

  • Node.js 18+
  • macOS: Xcode Command Line Tools — xcode-select --install

Development

npm install
npm run dev

Building

# 1. Compile with electron-vite
npm run build

# 2. Package distributable
npm run dist          # macOS .dmg (arm64 + x64)
npm run dist:win      # Windows NSIS installer
npm run dist:linux    # Linux AppImage + .deb

Output goes to dist/.

Code Signing (macOS)

Without certificates the app is signed ad-hoc — fine for local testing. For a signed and notarized release:

export CSC_LINK=/path/to/certificate.p12
export CSC_KEY_PASSWORD=...
export APPLE_ID=you@example.com
export APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx
export APPLE_TEAM_ID=XXXXXXXXXX
npm run build && npm run dist

Verify Signing

codesign -dv --verbose=4 dist/mac-arm64/eTty.app
spctl -a -vvv -t install dist/mac-arm64/eTty.app

Architecture

┌────────────────────────────────────────────────────────────────────────┐
│                         Main Process                                   │
│  ┌──────────┐ ┌──────────┐ ┌──────────────────────────┐              │
│  │PtyManager│ │FileManager│ │   HistoryManager        │              │
│  │ node-pty │ │ fs ops   │ │   global + per-tab      │              │
│  └──────────┘ └──────────┘ └──────────────────────────┘              │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐               │
│  │GitService│ │ TabState │ │SettingsStore│ │AgentService│              │
│  │ countDiff│ │ persist  │ │ JSON config  │ │ detect CLI │              │
│  └──────────┘ └──────────┘ └──────────────┘ └────────────┘               │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ AppService — window, menu, auto-updater, state save on quit       │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐        │
│  │pty-handl│ │fs-handl │ │git-handl│ │tabs-hand│ │settings │ ...    │
│  │ ers     │ │ ers     │ │ ers     │ │ ers     │ │-handlers│        │
│  └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘        │
└──────────────────────────┬───────────────────────────────────────────┘
                           │ IPC (~50 channels, constants in shared/)
┌──────────────────────────┴───────────────────────────────────────────┐
│                    Preload (contextBridge)                             │
│                ~50 methods on window.electronAPI                     │
└──────────────────────────┴───────────────────────────────────────────┘
                           │
┌──────────────────────────┴───────────────────────────────────────────┐
│                       Renderer Process                                 │
│  ┌─────────────────────────────────────────────────────────────────┐  │
│  │ Core Infrastructure                                              │  │
│  │  EventBus  │  StateStore  │  DI Container  │  ElectronApiAdapter │  │
│  │  GitStatusService (polling)                                      │  │
│  └─────────────────────────────────────────────────────────────────┘  │
│  ┌────────┐ ┌────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐  │
│  │Terminal│ │FileTree│ │EditorPanel│ │ GitPanel │ │SettingsPage  │  │
│  │xterm.js│ │ lazy   │ │CodeMirror │ │  diff    │ │ overlay    │  │
│  │ tabs   │ │ DnD    │ │ 20+ langs │ │ branches │ │ themes     │  │
│  └────────┘ └────────┘ └──────────┘ └──────────┘ └──────────────┘  │
│  ┌────────┐ ┌────────────────┐ ┌─────────────────────────────────┐  │
│  │ TabBar │ │ ProjectSearch  │ │            StatusBar            │  │
│  │reorder │ │  dialog        │ │  git ±  │  cwd  │  AI agents   │  │
│  └────────┘ └────────────────┘ └─────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────┘

Architecture Patterns

The codebase follows a layered architecture after a 4-block refactoring:

  • DI Container (renderer/core/container.js) — components receive dependencies via constructor injection, not global variables
  • EventBus (renderer/core/event-bus.js) — pub/sub communication between decoupled components
  • StateStore (renderer/core/state-store.js) — centralized reactive state with subscriptions (ui.theme, ui.sidebarVisible, etc.)
  • IPC_CHANNEL constants (shared/ipc-channels.js) — single source of truth for all IPC channel names, no string literals
  • IPC handler modules (main/ipc-handlers/*.js) — each domain group in its own file with register*Handlers(ipcMain, deps) signature
  • AppService (main/services/app-service.js) — application lifecycle in main process (window, menu, updater, state save)

Data Storage

All user data is stored in ~/.config/eTty/ (Electron userData):

File Purpose
settings.json App settings (theme, focus indicator, file tree behavior, prompt style, agent proxy, force-disabled agents, quick replies)
tabs-state.json Saved tab state for session restore
history/global.zsh_history Shared command history (5000 lines)
history/tabs/<id>.zsh_history Per-tab command history

Notes

  • node-pty is a native module. electron-builder rebuilds it automatically via npmRebuild: true.
  • build/entitlements.mac.plist contains macOS entitlements required for node-pty under hardened runtime (JIT, unsigned memory, library validation).
  • Auto-update is stubbed — logs only, no update server configured yet.
  • Settings overlay blocks tab switching to prevent focus leaking to hidden terminals.

License

Private

About

one more terminal app!

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors