Yeesh

Yeesh

A LiveView terminal component with sandboxed command execution.

Yeesh provides a browser-based CLI with fish/zsh-like features (tab completion, command history, prompt customization) and Dune-powered sandboxed Elixir evaluation.

Features

Installation

Add yeesh to your dependencies in mix.exs:

def deps do
  [
    {:yeesh, "~> 0.1.0"}
  ]
end

Install the JavaScript dependencies:

npm install --prefix assets @xterm/xterm @xterm/addon-fit @xterm/addon-web-links

Register the hook in your app.js:

import { YeeshTerminal } from "../../deps/yeesh/assets/js/yeesh/hook.js"

let liveSocket = new LiveSocket("/live", Socket, {
  hooks: { YeeshTerminal }
})

The hook imports @xterm/xterm/css/xterm.css, which esbuild extracts into a separate CSS bundle alongside your app.js output. Add a second stylesheet link in your root.html.heex to load it:

<link phx-track-static rel="stylesheet" href={~p"/assets/js/app.css"} />

Quick Start

Add the terminal component to any LiveView:

<.live_component
  module={Yeesh.Live.TerminalComponent}
  id="terminal"
  commands={[]}
  prompt="app> "
/>

This gives you a working terminal with all built-in commands: help, clear, history, echo, env, and elixir (sandboxed REPL).

Custom Commands

Implement the Yeesh.Command behaviour:

defmodule MyApp.Commands.Deploy do
  @behaviour Yeesh.Command

  @impl true
  def name, do: "deploy"

  @impl true
  def description, do: "Deploy the application"

  @impl true
  def usage, do: "deploy [environment]"

  @impl true
  def execute([], session), do: {:error, "specify an environment", session}

  def execute([env], session) do
    # Your deployment logic here
    {:ok, "Deployed to #{env}", session}
  end
end

Register it in the component:

<.live_component
  module={Yeesh.Live.TerminalComponent}
  id="terminal"
  commands={[MyApp.Commands.Deploy]}
/>

Elixir REPL

The built-in elixir command provides a sandboxed Elixir evaluation environment powered by Dune:

$ elixir 1 + 2
3
$ elixir
Entering sandboxed Elixir REPL (powered by Dune).
Type 'exit' to return to the shell.
iex> x = 42
42
iex> x * 2
84
iex> exit
$

Variables persist within the session. Dangerous functions (file system, network, code loading) are restricted by Dune's allowlist.

Configure the sandbox:

<.live_component
  module={Yeesh.Live.TerminalComponent}
  id="terminal"
  sandbox_opts={[timeout: 10_000, max_reductions: 100_000]}
/>

Configuration

Execution Model

Command execution is currently synchronous -- the LiveView process blocks until the command completes (with a configurable timeout, default 5s).

Async streaming execution is planned for Milestone 3.

Roadmap

License

MIT