Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
0.9.13 - 2026-08-14
Changed
-
⌘Pis one search dialog with tabs. Files, Symbols, Actions and Text — Files by default.Tabcycles,⇧Tabgoes back, or click. Finding a file, a symbol, a command and a line of text used to be four overlays behind four shortcuts, which meant deciding what you wanted before you started typing. -
Move a class, and everything that points at it. Refactor: Move Class… takes the active file's fully-qualified name, asks for a new one, and shows what it would do before doing it: where the file goes, and every other file whose
useor fully-qualified reference changes. PSR-4 decides the destination, soApp\Domain\Orderlands inapp/Domain/Order.php— and a namespace with no PSR-4 mapping is refused rather than written somewhere Composer will never autoload.Matching is whole-name: moving
App\Models\OrderleavesApp\Models\OrderItemalone, andLegacy\App\Models\Orderis a different class. Aliased imports keep their alias, and a leading\is preserved. Renaming the class in the same move updates its declaration and self-references too, without touching a method that happens to share the name. -
Rename asks the language server, and shows you what it will do.
F2replaced whole-word matches in the active buffer and wrote them straight in — so it renamed inside strings and comments, missed every other file, and gave you no way to check before it happened.It now asks the language server, which knows which occurrences are the symbol and sees the whole workspace, then lists every site as it reads now and as it will read. Nothing is written until you confirm. Open buffers are changed through the document, so the rename is undoable; the rest are written to disk.
Where there is no language server, or it declines the rename, the old textual behaviour is still there as the fallback.
0.9.12 - 2026-08-13
Added
-
Test failures you can click. Running the suite reported an exit code and left you to find the failure by eye. Where the runner can write JUnit XML —
php artisan test, Pest, PHPUnit, Vitest — the TDD panel (⌘⇧T) now lists each failure with its first assertion line, and clicking one opens the file at the failing line. The toolbar shows12 passed · 2 failed · 1 skipped, since "the suite failed" and "two of ninety tests failed" are different news.Runners that can't produce a report are run exactly as before, with the plain output. Nothing is passed a flag it doesn't take.
-
Pint and PHPStan. The two tools a modern Laravel project's CI enforces, which the editor previously knew nothing about. Both are picked up from
vendor/bin, so a project that doesn't use them is unaffected.Pint becomes the formatter for PHP where the project ships it, taking precedence over the language server — a Laravel project's formatting is whatever Pint says it is, and letting Intelephense format to its own taste only produces a diff for Pint to undo.
pint.jsonis respected.PHPStan runs on save over the saved file, and its findings show up as warnings next to the language server's, each carrying the rule identifier (
variable.undefined) as its code. It needs aphpstan.neon, since that is what sets the level and paths. When PHPStan itself fails — a broken config, a missing path — the error is reported rather than swallowed, because a run that never looked at your code must not read as a clean one.
Fixed
-
Step debugging now works when PHP runs in a container. The Xdebug launch config sent an empty
pathMappings, so the adapter had no way to turn the/var/www/html/...paths Xdebug reports into files on disk — breakpoints simply never bound, with no error to explain why. Debugging worked for a nativephp artisan serveand not at all under Laravel Sail, which is how a large share of Laravel projects run.enow reads the project'sdocker-compose.ymland maps the bind mount of the project root, so a stock Sail setup needs no configuration. Named volumes and unrelated mounts are ignored, andE_PHP_PATH_MAPPINGStakes a JSON object for setups that can't be inferred. A project without a compose file gets no mapping, exactly as before.
0.9.11 - 2026-08-13
Added
-
Pull requests can carry measurement instead of description. The session review knew what changed and the runtime capture knew what a request costs; nothing joined them. Measure routes, in the ship gate next to Run tests, works out which routes the changeset actually reaches, replays each one with the change and again with your working tree stashed, and puts the result in the pull-request body:
Route Status Time Queries N+1 Verdict GET /orders200 340 → 95 ms 42 → 4 removed improved GET /reports200 → 500 90 → 5 ms 4 → 0 no broke PATCH /orders/{order}— — — — not replayed: would write An N+1 you introduced, a route that started failing, and a regression are called out as plainly as a win.
Attribution is conservative on purpose. A route is claimed only when a controller it dispatches to changed, or when a routes file changed and the diff mentions that route — editing
routes/web.phpdoes not make every route in the app suspect. Every claim carries the reason it was made, and changed files that trace to no route are counted under the table rather than dropped: measured 3 routes means something different when forty files went untraced.What it will not pretend to know. Write routes and routes needing URL parameters are listed but never replayed — firing a
PATCHat your app would change data, and guessing a parameter would measure a 404 and call it evidence. Without Clockwork the query and N+1 columns read not visible rather than zero, because "we could not see" and "there were none" are different claims. Where the changeset carries a migration, the section says so outright: stashing restores code but not your database, so the baseline ran old code against the new schema.Your uncommitted work is stashed and restored around the baseline. If the restore fails
esays so and tells you the work is ingit stash; a clean tree is no longer mistaken for lost work. Each pass also waits out PHP's opcache, which serves the previous bytecode for a couple of seconds after a file changes — without that the baseline silently measures the code that was just stashed away, and a change that removed a 25-query N+1 reports as4 → 4 queries, regressed.
0.9.10 - 2026-08-12
Changed
-
Large files no longer freeze while you type. Every keystroke re-parsed the whole document with tree-sitter and re-diffed it against
HEAD, synchronously on the UI thread. Files over 64 KB now do that work on a worker thread, debounced, keeping the previous colours on screen until the new ones land — a brief lag instead of a stall. Below 64 KB nothing changes; it stays inline so colours never trail the caret.The threshold is where it is because the work cannot be made cheap enough to keep inline: of the 112 ms a 188 KB Rust file costs, the tree-sitter parse alone is 45 ms and the highlight query most of the rest.
cargo test -p e-core --test highlight_cost -- --ignoredreproduces the measurements.
Fixed
-
Typing could abort the editor and lose unsaved work. A selection whose offsets outlived the text they were measured against — after a reload from disk, an agent edit or an undo-tree jump — reached the rope's CRDT engine as a malformed delta and tripped an assertion. So did two selections in one edit call that overlapped each other. Both fire inside a callback that cannot unwind, so the process aborted rather than panicking, taking unsaved changes with it. This was not theoretical; it is in
~/.config/e/crash.log, reached from ordinary keystrokes.Edit regions are now clamped to the buffer, and a region overlapping one already applied is dropped. Both paths are reproduced and pinned by tests in the vendored fork, including a 2000-case sweep of degenerate selections.
-
Syntax highlighting cost grew with the square of the file. Merging the overlay spans (inline SQL in PHP, Tailwind classes in Blade/HTML/Vue) over the base grammar's rescanned the overlay list from the front for every base span, making it O(base × overlay) — so a PHP file four times the size cost eight times as much. The merge now seeks to the first overlay that can apply. Measured per keystroke: 312 KB of PHP 2368 ms → 778 ms, 118 KB of Blade 330 ms → 81 ms, 78 KB of PHP 288 ms → 190 ms.
-
Workspace Replace All could rewrite your dependencies. The walker behind
⌘⇧Fskipped only dot-entries,targetandnode_modules, so a Laravelvendor/,storage/orpublic/build/was fair game — Replace All would edit Composer packages and build output. Search and replace now honour.gitignore, the global gitignore and.git/info/exclude. Avendor/you actually track (like this repo's vendored Floem) stays searchable. -
Search and Replace All disagreed about what matched. Search matched case-insensitively and reported only the first hit per line; replace matched case-sensitively and rewrote every occurrence. So the list you were shown and the edit you got were different sets, and the "replaced in N files" count quietly undercounted. Both now run through one walker and one matcher, and the results list shows every occurrence. A new Aa toggle in the search picker governs both at once.
-
Replace All now shows what it will do before it does it — how many matches, in how many files, which files, under which case setting — and writes nothing until you confirm. It previously wrote straight to disk with no preview and no undo.
-
Workspace search hit positions are derived from the original text rather than a lowercased copy, so the caret lands correctly on lines whose byte length changes under case folding.
-
The search query is matched literally, so
$user->name()finds that text instead of being interpreted as a pattern. -
~/.config/eno longer fills up with dead sockets. Every editor process created anagent-<pid>.sockfor the agent workspace sync and only ever removed its own on startup, so one file accumulated per launch, forever (186 of them on the machine this was found on). Stale sockets are now swept at startup. Liveness is decided by whether anything answers on the socket rather than by whether the pid is still around, since pids get recycled; sockets younger than 30 seconds are left alone so a starting editor can't be caught mid-bind.
Security
-
The agent sync socket was reachable by any local process. It was named
agent-<pid>.sockin a world-listable~/.config/e, with no authentication — so anything running on the machine could find it by globbing and callrun(arbitrary shell) ortinker(arbitrary PHP). The socket name now carries 96 bits of randomness, the directory is0700and the socket0600, and the path reaches agents only through$E_EDITOR_SOCK. Knowing that the editor is running is no longer enough to drive it.runandtinkerstill execute without a per-call prompt: the autonomous test-fix-rerun loop is built on them, and the fix was authenticating the channel rather than interrupting a designed workflow. The limits of that are now written down in agent-sync.md, which previously claimed "nothing is exposed". -
Database passwords are no longer kept in a world-readable file. Passwords, SSH passwords and SSH key passphrases were serialised in plaintext into
~/.config/e/databases.json, which was created with the process umask — 0644 in practice, so any account on the machine could read them. They now go to the OS credential store (macOS Keychain; Secret Service on Linux), keyed by a stable per-connection id so renaming a connection doesn't orphan its entry.databases.jsonkeeps only the non-secret fields and is written0600; an existing file is tightened as soon asereads it, not just when it next writes. Where no credential store is reachable, secrets stay in the (0600) file andesays so. Connections saved by earlier versions keep working and migrate on the next save.Building on Linux now needs
libdbus-1-dev— see docs/installation.md.
0.9.9 - 2026-08-01
Added
-
The official Laravel language server. In a Laravel project,
enow runslaravel/lspalongside Intelephense and merges their answers — Intelephense for general PHP,laravel/lspfor framework awareness: routes, views, translations, config, environment variables, assets/Mix, middleware, Inertia, Livewire, auth/policies, container bindings and validation rules, with completions, hovers, diagnostics (an unknown route or missing view is now a squiggle) and quick fixes. Blade files get a language server for the first time.Install it once with
composer global require laravel/lsp. If it isn't installed nothing breaks — you keepe's built-in Laravel intelligence. The newlaravel_lspsetting (on by default, restart to apply) switches between the two. -
Multiple language servers per language. The LSP client can now run several servers for one file and combine them: document sync goes to all of them, completions and code actions are merged, hover and go-to-definition take the first answer, and formatting/rename stay with the primary server.
Fixed
- Diagnostics could be silently dropped. The bridge from the LSP reader threads kept only the last message per frame, so diagnostics published close together could go missing until the next edit. They now travel through a drained queue. (This would have become systematic with two servers publishing for the same file.)
0.9.8 - 2026-07-28
Added
Session review (⌘⌥V) grew from “read the diff” into the whole path from an
agent's changes to a shipped pull request.
- Automated review flags.
einspects the diff itself and flags what agents tend to leave behind — debug statements (dd(,console.log(), hardcoded secrets, interpolated raw SQL, destructive migration steps,.envvalue changes, deleted authorization checks,eval/shell_exec/unsafe {, skipped or focused tests, weakened safety checks (rejectUnauthorized: false,chmod 777), removed tests and large one-sided deletions, plusTODOs and blockingsleep(s. Findings appear as a coloured dot per file and a list above the diff, each with Ask to send it straight to the agent. Matching is call-aware, soadd(isn't mistaken fordd(. - Ship gate. A verdict bar — Ready (all reviewed, tests green, no flags), Notes (loose ends) or Needs attention (failing tests or danger flags) — with the reasons spelled out, and Run tests to fill in the missing piece.
- Commit & PR. Ship the reviewed changeset without leaving the editor: it
creates a branch derived from what changed, commits in logical groups in
dependency order (
chore(deps)→feat(db)→chore(config)→feat(routes)→feat(auth)→feat→test→docs→ci) with Conventional Commits subjects, pushes, and opens a pull request viaghwhose description carries the summary, the grouped file list and the review evidence (files reviewed, test result, flag counts). - New sync-socket method
review_summary— the agent can hand back its own write-up of the session, which becomes the pull-request description.
0.9.7 - 2026-07-28
Added
-
Agent session review (
⌘⌥V, or Review: Session Changes). After an agent changes a pile of files, review the whole changeset locally instead of pushing and reviewing on GitHub:- Risk-ranked file list — migrations,
.env, config, routes, auth and dependency manifests surface first; lockfiles, tests and docs sink to the bottom. Each file shows a reason badge,A/M/D/R, and+N −M. - Sign-off flow with a progress counter (
12/50 reviewed) and Reviewed → to tick a file and jump to the next one that needs attention. - Per-file actions — Open (jumps to the first changed line), Ask why
(asks the agent to explain that file's change), and Revert (deletes the
file if the session created it, otherwise restores it from
HEAD). - Summarize asks the agent to describe the whole changeset and flag anything risky.
The session boundary is a git checkpoint taken when the agent starts. With no session recorded it reviews everything uncommitted, so it works just as well when the agent ran in an external terminal.
- Risk-ranked file list — migrations,
0.9.6 - 2026-07-24
Added
- Selectable terminal & agent output. Drag across output in the agent panel
or the integrated terminal to select it, and copy with
⌘C. A plain click still focuses the panel for typing — click again to resume after selecting. (Powered by the vendored Floem fork's selectablerich_text.) - Click-to-open file paths. A
path,path:lineorpath:line:colreference in agent/terminal output is now clickable and opens that file at the line in the editor. - Send selection to the agent (
⌘⌥S, or Agent: Send Selection to Agent in the command palette). Types a one-line reference to your current file and selected lines into the agent — without submitting — so you can add your question and let it read the exact spot. - “Editor integration” setting (Settings → Agents, on by default) gates the click-to-open and send-selection features.
0.9.5 - 2026-07-24
Added
- “Verify the fix” loop in the Runtime panel. Click the ✓ on a captured
request to take a baseline measurement (it checkpoints your working tree,
replays the request, and records time / query count / N+1). Apply a fix
(edit code or ask the agent), hit Measure again, and get a before/after
verdict — Improved / No change / Regressed / Broke — then Keep the change
or Discard it (which reverts to the checkpoint). Backed by the pure,
unit-tested
e-verifymetrics +e_core::gitcheckpoint/restore. - Selectable markdown. The
.mdreading preview is now selectable — drag across headings, bold, inline code and links and copy (⌘C) with the formatting intact. This is powered by our vendored Floem fork (below), which adds text selection to rich text.
Changed
- The agent panel (⌘L) uses the terminal by default for every agent, including Elyra. The native RPC-rendered chat panel from 0.9.0 wasn't interactive enough on the current text/input views, so every agent now runs in the terminal panel out of the box. The native panel is still available as an experimental, opt-in toggle — Settings → Agents → “Native Elyra chat” (off by default).
- The agent panel opens wider —
⌘Lnow starts at 600px (still resizable from 300–900px). - Vendored the Floem UI toolkit into
vendor/floem.enow builds against its own copy of Floem instead of a pinned git revision, so we can extend the editor/text/input views ourselves (starting with selectable rich text) rather than being limited by upstream. Seevendor/floem/FORK.md.
0.9.4 - 2026-07-23
Fixed
- “Check for updates” no longer reports “up to date” when the check actually failed. A failed request (e.g. GitHub's unauthenticated rate limit, 60/hr) was silently treated as “no update”; it now shows a distinct Couldn't check for updates notice with a Retry. The silent startup check is also throttled to once every 6 hours so frequent restarts don't exhaust the rate limit (a manual check always runs).
0.9.3 - 2026-07-23
Added
- Recent projects on the welcome screen. The empty-state screen now lists your recently-opened projects (most-recent-first) — click one to open it — so a fresh launch from the Dock has somewhere to go, Zed-style.
Changed
- The agent transcript is now selectable. You can drag-select and copy
(
⌘C) any text in an assistant reply. Block structure (heading sizes, code boxes with a Copy button, list bullets) is preserved; inline emphasis within a paragraph is rendered as plain text, since floem's selectable text is single-style. User messages and reasoning are selectable too.
0.9.2 - 2026-07-23
Fixed
- Native agent panel did nothing when launched from Finder/Dock. The agent
is now started through your login shell (
$SHELL -lc), so the fullPATH(nvm/npm, Grove'snode, etc.) is available — a bundled.appinherits only a minimalPATH, soelyra(and thenodeits shebang needs) couldn't be found by a direct spawn, and prompts silently went nowhere. Your message is now also shown immediately, and a clear error appears in the panel if the agent can't be started.
0.9.1 - 2026-07-19
Fixed
- Unsaved “untitled” tabs are no longer lost on quit. Scratch buffers with content are now saved in the workspace session (and backed up periodically while you type) and recreated as untitled tabs the next time you open the project — no more losing notes because you closed the window without saving.
- macOS: the app now fully quits when you close the window — the process and
its Dock icon no longer linger (floem defaults to don't exit on close on
macOS;
eis single-window, so it exits).
0.9.0 - 2026-07-19
Added
- Native agent chat panel (
⌘L). Elyra now runs headless over its structured RPC protocol (elyra --mode rpc) and the conversation is rendered with native views instead of the agent's terminal UI inside a PTY — removing the per-frame ANSI re-parse that made the panel feel laggy. It brings:- Streaming replies rendered as formatted markdown — headings, lists, inline code, fenced code blocks and links, with comfortable line-height.
- Tool-call cards showing the tool, a one-line argument summary, status (running / done / error) and a compact result preview.
- A multi-line composer that word-wraps and auto-grows with your text (up to ~7 lines, then scrolls); Enter sends, Shift+Enter inserts a newline. It is focused automatically when the panel opens.
- A real Stop button (abort), steering while the agent is running, and New Chat.
- Copy buttons on fenced code blocks and under each assistant message.
- Other agents (Claude Code, Codex) keep the terminal panel. Toggle the native
panel with the
native_agentsetting (default on).
e-agentcrate — a small, fully-tested RPC client (a lenient JSONL protocol decoder plus a reducer that folds the event stream into a renderable conversation) that powers the native panel.- Crash logging. Unhandled panics are appended to
~/.config/e/crash.log(message, location and backtrace) so GUI-only crashes can be diagnosed.
0.8.3 - 2026-07-08
Fixed
- macOS: “cannot open files in the ‘folder’ format”. The app bundle now
declares that it accepts folders, so opening a folder via Open With → e (or
dropping one on the icon) no longer errors. Opening folders from the CLI
(
e <folder>) and with⌘Oalready worked.
0.8.2 - 2026-07-07
Added
- EditorConfig support.
.editorconfigis honoured per file: indent size / tab width, andtrim_trailing_whitespace/insert_final_newlineon save (overriding the global On-Save settings). Full glob matching (*,**,?,{…}) with root-stop and nearest-wins resolution. - Compare files. Compare Active File With… (command palette) shows a line diff between the current file and any file you pick.
- Code actions / refactor.
⌘.requests LSP code actions (quick fixes, extract variable/method, …) at the cursor or selection and applies the chosen one — where the language server supports it.
0.8.1 - 2026-07-06
Added
- Column editing.
⌥⌘↑/⌥⌘↓add a caret one line above / below at the same column, growing a vertical multi-cursor — the keyboard form of column selection. Also available from the command palette.
0.8.0 - 2026-07-04
A major expansion of the database tools — the full “PhpStorm-parity and beyond” PRD, phases 1–5. The Database panel (⌘3) is now a complete daily driver.
SQL console (phase 1)
- Real editor with SQL syntax highlighting, schema-aware completion (tables/columns/keywords), and a draggable resize handle.
- Multi-statement runs:
⌘↵runs the selection or the statement under the cursor,⌘⇧↵(or Run) runs everything; each statement gets its own result tab (pinnable). - Query history persisted per project (searchable; click to reload).
- Named parameters:
:paramplaceholders prompt for values (remembered). - Cancellable runs; duration + row counts shown per run.
Safe editing (phase 2)
- Transactional editing: cell edits and row deletes stage as pending (amber cells, red rows) with a Submit (one transaction, via a confirmation dialog) / Revert bar.
- Environment labels (local / staging / production) with colour, on each connection and the active result.
- Destructive-statement and non-local write confirmation dialogs.
- Pagination with total count + jump-to-page; value viewer with JSON pretty-printing; explicit NULL handling.
Data in/out (phase 3)
- Export results as CSV / JSON / SQL inserts; copy as TSV / Markdown.
- CSV import into a table (header mapping, one transaction).
- Views in the object tree; search the tree.
Power tools (phase 4)
- EXPLAIN findings banner + EXPLAIN a query straight from the Runtime panel; agent-suggested index migrations.
- Generate/Copy DDL; related rows via reverse foreign keys; seed rows through an Eloquent factory.
Beyond parity (phase 5)
- Database snapshots (SQLite copy / mysqldump / pg_dump), local only.
- Session undo-log of writes (with generated reverse statements).
- Schema relationships (ERD) view; search a value across all tables; row counts in the tree; generate a migration scaffold from Structure.
0.7.7 - 2026-07-04
Added
- SQL console is now a real editor. The database panel's query box is a syntax-highlighted SQL editor (multi-line, monospace) instead of a plain text input, and it's resizable — drag the handle below it for more room.
- Schema-aware completion in the console. As you type SQL, table and column names (from the connected database) and keywords are suggested; ⌘↵ runs the console. Reuses the inline-SQL engine.
0.7.6 - 2026-07-03
Added
- Cell value viewer. Single-click a cell in the data grid to dock a read-only inspector at the bottom of the panel showing the full value — JSON objects and arrays are pretty-printed. Double-click still edits. (PhpStorm-style.)
Fixed
- Laravel settings tab overflowed the dialog. The content pane sized itself to its widest row, pushing toggles and the App URL field off the right edge with a horizontal scrollbar; the pane is now pinned to the dialog width.
0.7.5 - 2026-07-03
Fixed
- Keyboard navigation in the completion popup didn't work. Up/Down to move
the selection and Enter/Tab to accept were silently ignored, so completions
(Flux UI, Livewire, Laravel, LSP, …) could only be taken with the mouse. The
handler was registered through the editor builder's
.pre_command(), which only attaches to a plainTextDocument; because the editor uses a custom document wrapper for inlay hints and ghost text, the registration was dropped on the floor. It's now registered directly on the backing document, so the arrow keys and Enter/Tab drive the popup again — fingers stay on the keyboard.
0.7.4 - 2026-07-03
Added
- Click to accept a completion. Completion suggestions can now be inserted with the mouse — click a row to select and apply it (previously only Enter/Tab worked). Combined with the 0.7.3 crash fix, accepting a suggestion (including Flux UI / Livewire / framework completions) now works reliably.
0.7.3 - 2026-07-03
Fixed
- Crash when editing (pressing Enter, etc.). Recording an edit into the undo tree held a mutable borrow while bumping the revision counter, whose effect synchronously re-read the same undo tree — a double borrow that aborted the app (“e quit unexpectedly”). The borrow is now released before the update.
0.7.2 - 2026-07-03
Fixed
- Command palette showed stale results. The results list keyed its rows on position alone, so as you typed, floem reused the view at each slot and left the previous labels in place (e.g. typing “che” listed unrelated commands and hid “Check for Updates”). Rows are now keyed on the command identity, so the list rebuilds correctly as the filter narrows.
Added
- Delete rows & foreign-key hopping. The cell edit dialog now has a Delete
row action (honouring the read-only guard and requiring a primary key) and a
Follow FK → action that jumps to the referenced table filtered to the
linked value. Backed by new tested
e-dbprimitivesinsert_row,delete_row(with an empty-predicate guard so it can never wipe a table),fk_targetandrows_where. - Column filters. Filter to value in the cell dialog restricts the data
view to rows matching that cell (
WHERE col = value/IS NULL), composing with sort and pagination. An active filter shows as a chip in the toolbar — click it to clear. - Insert rows. A + Row button on the data toolbar opens a dialog with one field per column (each with a NULL toggle). Blank, non-NULL columns are omitted so database defaults / auto-increment apply. Honours the read-only guard.
0.7.1 - 2026-07-03
Added
-
EXPLAIN + agent index suggestions. With the cursor in a SQL string, Explain SQL Under Cursor (
⌥⌘⏎) runs the engine's EXPLAIN, shows the plan in the result panel, and flags full table scans / missing indexes. Suggest Index for SQL Under Cursor then hands the query + findings to the AI agent, which proposes a Laravel migration adding the index — EXPLAIN → diagnosis → ready-made migration in one flow (MySQL, PostgreSQL, SQLite). -
Index view. The Structure tab now lists a table's indexes (name, unique vs plain, and the columns each covers) below its columns — for MySQL, PostgreSQL and SQLite. Useful for spotting missing indexes behind slow queries.
-
Database write protection. Connections that look like production (SSH tunnels, non-local hosts, or names containing prod/production/live) default to read-only, and cell edits to a read-only connection are blocked with a warning — guarding against accidental writes to a real server over an SSH tunnel. A lock badge (🔒/🔓) on each connection shows and toggles the state.
-
Inline SQL intelligence. Raw SQL inside PHP (
DB::select("…"),->whereRaw('…'), migrations'DB::statement("…"), …) is no longer a dead string:- Syntax highlighting via the tree-sitter SQL grammar (detected from the PHP parse tree; double- and single-quoted; plain strings untouched).
- Schema-aware completion — typing inside the SQL string suggests table
names after
FROM/JOIN/UPDATE/INTOand column names elsewhere, from the live database schema cache. - Run the query under the cursor with
⌘⏎(or “Database: Run SQL Under Cursor”): executes it against a connected database and shows the results in the DB result panel.
Highlighting + schema validation + one-key execution in the same editor — without a separate database tool.
Fixed
- Command palette (
⌘⇧P) now actually filters as you type. The real cause wasn't just a stale query (0.7.0) — its query/selection lived onAppState(a different reactive scope), so thetext_inputand the results list didn't stay in sync and the list stayed on the unfiltered set. The palette now uses view-local signals like the file finder, so typing filters live.
0.7.0 - 2026-07-03
Fixed
- Command palette (
⌘⇧P) felt unresponsive. It didn't clear the previous query on open, so new keystrokes appended to a stale search (e.g.chebecame<old>che) and matched nothing. It now starts fresh every time — typing filters immediately.
Changed
- Reopen the last project. Launching
ewith no path (double-click, Dock, baree) now reopens the project you last had open instead of the current directory.
Added
- Inline AI completion (“ghost text”). After a short idle in a code file,
easks a local Ollama code model (fill-in-the-middle) for a one-line continuation and shows it as grey text at the cursor;Tabaccepts it, typing orEscdismisses it. Entirely local and opt-in — enable it in Settings → Editor (ai_completion), with the model set viaE_COMPLETION_MODEL(defaultqwen2.5-coder). Requests are debounced and never block the editor; nothing runs unless it's enabled and Ollama is reachable.
0.6.9 - 2026-07-03
Added
- Linux releases. Each release now publishes Linux binaries
(
e-x86_64-unknown-linux-gnu.tar.gzande-aarch64-unknown-linux-gnu.tar.gz) alongside the macOS builds, so the in-app auto-updater works on Linux too. A Linux build+test job was added to CI to catch platform breakage early. See installation for the system libraries needed.
0.6.8 - 2026-07-03
Fixed
- Silent write failures are now surfaced. A failed disk write during a
Livewire property rename or an applied agent edit (full/read-only disk) used
to report success anyway — risking a class and its view drifting out of sync.
Writes now notify on failure and only report success when the change landed;
agent edits reply
ok: falseinstead of claiming success. - Database lock hardening. A poisoned connection mutex in
e-db(a thread panicking while holding the lock) no longer crashes the whole editor — the guard is recovered and the query returns normally or errors cleanly.
Changed
- Modal overlay panels are registered as one
(open-signal, view)list, so the "is anything open?" guard is derived automatically. Adding a panel is a single line and can no longer desync the two lists — the bug class behind the 0.6.5/0.6.6 unclickable-window regressions.
Internal
-
Split the
state.rsgod-module: cohesive feature clusters now live in their own files (runtime.rs,db_state.rs,terminal_state.rs,laravel_state.rs,completion_state.rs,navigation.rs,tdd_state.rs), each extendingAppStatefrom its own module. Pure moves, no behaviour change;state.rsis down ~2,245 lines (6,599 → 4,354, −34%), leaving mostly irreducible core state (the constructor, buffers, LSP, save/format, diagnostics, cursor, tabs). A newAppState::spawn_bghelper centralises the background-work + UI-marshal boilerplate. -
A CI “Parser corpus” job runs the heuristic parsers (routes/views, Eloquent relationship + event graphs, Livewire/Inertia props) over real Laravel projects (laravel, pingcrm, livewire, laravel-permission), asserting “no panic, sane counts” — catching wild-PHP edge cases the happy-path unit tests miss.
-
macOS: "e cannot open files of this type". Opening a file via Finder ("Open With → e", double-click, or the Dock) no longer fails — the app bundle now declares
eas a text editor for all file types, so.sql,.env,.logand anything else are accepted. Files already opened fine by dragging onto the window, via⌘O, ore <file>from the CLI; this removes the OS rejection for the Finder path. (Rebuild the app / install the next release; macOS may take a moment to refresh its file associations.)
0.6.7 - 2026-07-03
Added
e-dapcrate — a synchronous Debug Adapter Protocol client (sibling toe-lsp, same architecture: protocol client in its own crate, background reader thread, id-correlated blocking requests). Reuses the identicalContent-Lengthstdio framing but dispatches on DAP'srequest/response/eventshape, correlates responses byrequest_seq, delivers adapter events to a handler, and answers reverse requests. Typed helpers cover the full step-debugging flow:initialize,launch/attach,setBreakpoints,configurationDone, step controls,threads/stackTrace/scopes/variables, andevaluate. This is the editor half of native debugging; paired with Grove'sgrove debug on, PHP/Xdebug works, and JS (js-debug) / Rust (codelldb) come nearly free since the client is adapter-agnostic.- Debug panel + step-debugging in the UI. A new Debug overlay shows session
status, execution controls (start/continue, step over/into/out, stop), the
live call stack (click a frame to jump to source), current-frame variables,
and all breakpoints. Breakpoints show as a red dot in the editor margin, and
the line execution is paused on is highlighted; stopping auto-jumps to it.
Keybindings: F5 start/continue, F9 toggle breakpoint on
the caret line, F10 step over, F11 step into, ⇧F11 step out; all also in the
command palette (“Debug: …”). The adapter (
vscode-php-debug) is launched over Grove's bundled Node automatically (discovered from Grove'snode-builds.json, falling back tonodeon PATH); the adapter path is auto-detected from installed VS Code/Cursor extensions orE_PHP_DEBUG_ADAPTER. Pair withgrove debug onand step-debugging PHP works end to end. - Multi-language debugging.
e-dapnow speaks DAP over TCP as well as stdio, so beyond PHP (Xdebug) the debugger also drives JavaScript/TypeScript viavscode-js-debugand Rust/C/C++ viacodelldb(both DAP servers). The adapter is chosen from the active file's language and auto-discovered from installed VS Code/Cursor extensions (overridable viaE_JS_DEBUG_ADAPTER,E_CODELLDB,E_DEBUG_PROGRAM). - Alt-click in the editor toggles a breakpoint on the clicked line (Floem's built-in gutter isn't clickable), and breakpoints set before a file is opened now appear when it opens.
- Settings: Enable Xdebug (Settings → Laravel,
xdebuginconfig.json) — toggling it runsgrove debug on/offso you can start step-debugging without the terminal. On startup the toggle is synced from Grove's real state (grove debug status). Degrades gracefully when Grove isn't installed.
Fixed
- Debugging is fully opt-in and never affects the editor when Grove/Xdebug or a DAP adapter aren't installed: the adapter is now launched entirely off the UI thread, so a missing or slow adapter (including the TCP connect for JS/Rust) can't freeze the editor, and missing tools report a clear status instead.
0.6.6 - 2026-07-02
Fixed
- The file explorer and editor were unclickable: an overlay group wrapper introduced in 0.6.5 covered the whole window and swallowed every click. It now only covers the window when one of its panels is open.
⌘Pnow finds hidden files (.env,.gitignore, …); they were excluded from the file index.
0.6.5 - 2026-07-02
Added
- Query-builder completion: column names inside
where(),orderBy(),select(),pluck(),value(),groupBy(), … and relationship names insidewith(),load(),whereHas(), resolved from the model/table and the live schema. Unknown columns are flagged inline (Column emial not found in table users) — something PhpStorm can't do without the database. - Related files (
⌘⌥E): jump between the model, migration(s), factory, seeder, controller, policy, request, resource, and test for the same resource. - Validation intelligence: completion for rule names in
validate([…])/ FormRequestrules(), plus a command to generate rules from a table's live schema (nullability, string lengths, types). - Gates & policies: completion and go-to-definition for abilities in
can(),authorize(),@can, andGate::allows()→ the policy method. - Generate model from table: builds an Eloquent model from the live schema — fillable, casts, and relationships inferred from the actual foreign keys.
- Event dispatch graph (
⌘⌥G): events → listeners (from$listen,Event::listen, and auto-discoveredhandle()types), withF12on a dispatched event jumping to a listener.
Changed
- The file explorer now shows hidden files (
.env,.gitignore,.github, …). Only.git,node_modules, andtargetare hidden.
0.6.4 - 2026-07-02
Added
- Inertia awareness.
Inertia::render('Users/Index')now resolves likeview(): go-to-definition and completion reach the page component underresources/js/Pages, and the architecture map goes route → controller → page component instead of stopping at the controller. - Props contract (
⌘⌥C): reconciles a page component with the controller that renders it — infers TypeScript types from the render call (User::paginate()→User[], fields from the live schema), flags props sent but unused and props used but never sent, and generates TypeScript interfaces expanded from the real database schema. Also reconcilesuseFormfields against the matching FormRequest's validation rules. - Ziggy route intelligence on the JS side:
route('name')in JS/TS/Vue/Svelte gets completion, hover, and go-to-definition from the same Laravel route table the PHP side uses. - Shared props:
HandleInertiaRequests::share()is parsed so$page.props.auth.userand friends complete everywhere. - Inertia-aware request replay: the replay renders an Inertia response as an explorable props tree (with the component name, click to open) instead of raw HTML.
- Livewire refactoring:
wire:modelcompletes from the component class's public properties,⌘⌥Jswitches between the view and class,F12on a property jumps to its declaration, and renaming a property (F2) updates both the class and everywire:reference in the view. - Runtime insight (
⌘⌥I): a continuous Telescope-style panel that captures every request against the dev app via Clockwork — queries with N+1 warnings, cache hits/misses, mails, and events — with "Explain with agent" one click away. No Telescope or Debugbar needed.
0.6.3 - 2026-07-02
Added
- Eloquent relationship graph (
⌘⌥R): parseshasMany/belongsTo/belongsToMany/morph*from your models and cross-checks them against the live database's foreign keys — flagging relations that exist in code but have no backing FK. Together with the schema diff it shows code, migrations, and the actual database in one picture. - Security lens on the architecture map (
⌘⌥M): each route shows its middleware and a 🔒 / ⚠ badge; state-changing routes with no authentication are flagged, and one click asks the agent to suggest protection. - Generate a Pest test from a request replay: the 🧪 button writes a feature test
with the path, status, and assertions derived from the actual response, ready
for the
⌘⇧T"fix to green" loop.
0.6.2 - 2026-07-02
Changed
- Redesigned the settings dialog (
⌘,) into a two-pane layout: a category sidebar plus a search box that filters settings across every category, with hairline row dividers, per-row "restart" badges, and an "Open config.json" footer link. Close withEscor the ✕. - The command palette (
⌘⇧P) now uses fuzzy, ranked matching instead of a plain substring filter — typingupsurfaces "Check for Updates" and "Move Line Up" first, and the selection resets to the best match as you type.
0.6.1 - 2026-07-02
Added
- Semantic search (⌘⌥K): a "describe what you're looking for" mode that ranks project locations by meaning. Runs locally — uses a local Ollama embedding model when available, with a lexical fallback otherwise.
- Visual undo tree (⌘⌥U): a branching history that preserves edits a linear undo would discard, with click-to-jump time travel persisted across sessions.
Changed
- Release builds are now signed with a Developer ID and notarized by Apple, so the DMG opens without Gatekeeper warnings. CI signs automatically when the signing secrets are configured (see docs/installation.md).
- Added the missing ⌘3 (Toggle database) shortcut to the welcome screen.
0.6.0 - 2026-07-02
Added
- Schema diff (command palette): compares migrations against the live database and flags columns present in one but not the other.
- Eloquent completion from the live database schema: typing
$model->suggests the real table columns (inferred model → table), merged with the language server. - Live
laravel.logpanel (⌘⌥L): tails the log with coloured levels, clickable stack frames, and a "Fix with AI" action. - Request-replay from the architecture map (⌘⌥M): a ▶ button on GET routes hits
the running app (Grove
https://<folder>.testby default, configurable via the App URL setting) and shows the response plus the SQL queries it ran (via Clockwork) with N+1 detection and "Explain with agent". - Autonomous TDD panel (⌘⇧T): run the test suite with pass/fail status, and a "Fix to green" loop where failures are sent to the agent, its proposed edits are reviewed, and tests re-run automatically until green (with an iteration cap and Stop).
- Agent
propose_edit: agents propose a new file version and you review it hunk-by-hunk (accept/reject each change) before applying — no blind writes. - Agent timeline (⌘⌥A): an audit log of everything the agent does over the socket, and a 🤖 marker in the status bar showing where the agent is looking.
0.5.1 - 2026-07-01
Changed
- The welcome screen shows a minimalist, transparent app glyph instead of the boxed icon.
- The Settings dialog (⌘,) has consistent row spacing and a darker backdrop.
- The macOS "About e" menu-bar panel now shows the app icon, version, tagline and links (matching the ⌘⇧P About box's content).
0.5.0 - 2026-07-01
Added
- Agent co-op over the sync socket:
lsp_definition/lsp_references/lsp_hover/lsp_symbols(reuse the running language server),db_schema(read the connected database's schema without exposing credentials),db_query(agent-proposed queries run only after you approve them in a consent dialog),runandtinker(execute commands/PHP and capture the output — the basis for autonomous TDD). - "Explain with agent" on failed database queries, and a "Fix with AI agent" action on problems, both prompt the agent panel directly.
- Laravel Tinker scratchpad (⌘⌥T): run PHP against the app and see the output; "Tinker: Run Selection" evaluates the current selection.
- Laravel architecture map (⌘⌥M): an interactive route → controller → view flow with clickable cards that jump to the code.
Changed
- The app icon now appears in the About dialog and the welcome screen, and the bundle icon was refreshed.
0.4.9 - 2026-06-29
Added
- AI Agent Workspace Sync: the editor exposes a local socket (
$E_EDITOR_SOCK) so a CLI agent can read editor context (current file, cursor, selection, diagnostics) and drive the editor (open a file at a line, focus a panel, notify). See agent-sync.md.
0.4.8 - 2026-06-29
Added
- Terminal scrollback (5000 lines): scroll up with the mouse wheel to review earlier output; the view stays anchored while output streams and snaps back to the bottom when you type.
- Terminal background colours (SGR 40–47/100–107 and 256/true-colour) —
git diff, coloured errors and search tools keep their highlighting.
Changed
- SSH passwords are no longer written to disk: the askpass helper reads the secret from an environment variable that only lives in memory.
- External-change file polling runs off the UI thread, so the editor never stalls on slow or network filesystems.
- External reloads honour the file's detected encoding (UTF-16/Windows-1252).
Fixed
- Language servers now shut down gracefully (shutdown + exit) and their stderr is logged instead of discarded, making LSP issues diagnosable.
0.4.7 - 2026-06-29
Added
- The terminal panel (⌘T) is now drag-resizable in height — drag the handle along its top edge.
Fixed
- The agent panel (⌘L) could not find CLI agents installed via nvm
(
command not found) when the app was launched from Finder; agents now run through an interactive login shell so.zshrc/.bashrcPATH is available.
0.4.6 - 2026-06-29
Added
- Source Control: a ✨ button suggests a Conventional Commits message (type, scope and changed files) generated from your staged changes.
Changed
- Project links now point to elyracode.com (About dialog, README docs link and Cargo metadata).
0.4.5 - 2026-06-28
Added
- Tailwind CSS highlighting inside
class="…"attributes (Blade, HTML, Vue): utility classes, variant prefixes (sm:,dark:,hover:) and arbitrary values (w-[680px]) are coloured distinctly.
0.4.4 - 2026-06-28
Changed
- Blade syntax highlighting now colours Blade directives,
{{ }}/{!! !!}expressions,{{-- comments --}}and the embedded PHP inside@phpblocks and echoes — in addition to HTML, attributes and Tailwind classes.
0.4.3 - 2026-06-28
Changed
- The
⌘Pfile finder now uses ranked fuzzy matching (file-name and short-path matches rank highest, e.g.wbpfindswelcome.blade.php) and builds its index in the background, so it opens instantly even on very large folders.
0.4.2 - 2026-06-28
Added
- Emmet abbreviation expansion (Tab) in HTML, Blade, Vue, Svelte and PHP:
tags, classes, ids, attributes, text, nesting, grouping, multiplication and
$numbering.
Fixed
⌘W/Escnow close the database results overlay (and the cell-edit popup).
0.4.1 - 2026-06-28
Added
- Database: inline cell editing (double-click a cell in a table with a primary key), saved queries (per project), ClickHouse support (HTTP interface), and SSH tunnels for remote databases.
Changed
- New application icon.
0.4.0 - 2026-06-28
Added
- Database panel (⌘3): browse and query MySQL/MariaDB, PostgreSQL and SQLite
databases. Connect from the project's
.envor manually (with a Test button), browse tables with sortable columns, paging, a Data/Structure view and CSV export, and run SQL in a results grid (⌘↵ to run, horizontal scroll and arrow keys to pan). Right by default; configurable left. - Laravel features on par with the official VS Code extension: completion, hover
and go-to-definition for
route(),view(),config(),env(),__()/trans()and<x-...>Blade components, sourced from your project viaphp artisan. Auto-enabled in Laravel projects; toggle under Settings → Laravel features.
0.3.3 - 2026-06-28
Added
- Line-ending conversion: click LF/CRLF in the status bar to convert the buffer.
- Non-UTF-8 files now open (BOM detection + Windows-1252 fallback); the detected encoding is shown in the status bar and preserved on save.
Changed
- Large files (>1MB) skip tree-sitter highlighting, git markers, blame, inlay hints and bracket matching to stay responsive.
0.3.2 - 2026-06-28
Added
- Multi-root workspaces: "Add Folder to Workspace" adds more root folders; the explorer, file finder and search span them all.
- Drag & drop files from Finder into the window to open them (folders open in a new window).
- Select all occurrences of the word/selection (⌘⇧L).
0.3.1 - 2026-06-28
Added
- Task runner (
⌘⇧B): detects npm/yarn/pnpm/bun, Composer, Cargo, Go, Laravel artisan, Pest/PHPUnit and Makefile tasks and runs the chosen one in a named terminal. "Run Tests" runs the project's test command. - Customizable keybindings: every action is a named command, rebindable in the
keybindingssection ofconfig.json. - Graphical settings page (
⌘,): toggles and steppers for the common options, applied live and persisted toconfig.json. The raw JSON is still available via "Open Settings (config.json)".
0.3.0 - 2026-06-27
Added
- Inlay hints: inline type and parameter-name hints from the language server,
shown as dimmed phantom text. Configurable via
inlay_hints. - Sticky scroll: the enclosing scope lines stay pinned at the top of the editor
as you scroll (indentation-based). Configurable via
sticky_scroll. - Workspace replace: the search panel (
⌘⇧F) now has a Replace row and "Replace All". - Source Control: branch switcher (click the branch name), recent-commit history, and stash (Stash / Pop).
- Editor tabs: drag to reorder, and right-click to pin (with Close Others).
- User-defined snippets in the
snippetssection ofconfig.json.
0.2.6 - 2026-06-27
Fixed
- After an in-place auto-update, the bundle Info.plist version is rewritten so the macOS About panel shows the correct version (previously stale).
- Dev/bundle scripts now stamp the real version from Cargo.toml into Info.plist.
0.2.5 - 2026-06-27
Fixed
- Clicking a command/file in the
⌘P,⌘⇧P,⌘Tand⌘Epalettes now runs the selection instead of just closing the palette (the close-on-blur fired before the click registered). - The update notice's "What's new" changelog now wraps properly and strips markdown noise, instead of overflowing horizontally.
0.2.4 - 2026-06-27
Added
- macOS DMG installer (
scripts/bundle-dmg.sh, also built per release) — drage.appinto Applications. Supports universal (arm64 + x86_64) builds and optional Developer ID signing/notarization. - "Install 'e' Command in PATH" command (⌘⇧P) — symlinks
einto/usr/local/binso you can launch the editor from any directory withe ..
0.2.3 - 2026-06-27
Added
- Framework-aware completion: Flux UI components (
<flux:…>), Livewirewire:directives, Tailwind utility classes (insideclass="…"), and Vue/Svelte directives. - File-type icons in the explorer, per language/extension, with open/closed folder icons.
Fixed
- Accepting a completion now places the caret at the end of the inserted text instead of in the middle (affected framework and LSP completions alike).
0.2.2 - 2026-06-27
Added
- Configurable panel layout:
sidebar_sideandagent_sidein settings move the explorer/Git sidebar and agent panel to the left or right (default: sidebar left, agent right).
Fixed
- The quick-open palettes (
⌘P,⌘⇧P,⌘T,⌘E) no longer stretch to the full window height — they size to their contents. - Typing in a palette now reliably reaches its input: the editor no longer steals keyboard focus while a palette or dialog is open (it re-focuses on close).
0.2.1 - 2026-06-27
Added
- Built-in completion that works with or without a language server: language keywords, identifiers already in the file, and — for PHP/Blade — Laravel facades and Blade directives. Merged with LSP and snippet suggestions.
- New file (
⌘N) creates an untitled buffer; Save As… (⌘⇧S) writes it to disk and reopens it with full language, LSP, and git support. - Complete user documentation in
docs/(installation, editing, navigation, languages, Laravel, source control, terminal, agents, configuration, updating, and troubleshooting).
Changed
- The editor now takes keyboard focus automatically when a buffer becomes active (new file, opening a file, switching tabs), so you can type immediately without clicking into it first.
0.2.0 - 2026-06-27
Added
- Git blame for the current line shown in the status bar.
- Merge-conflict resolution bar: accept current, incoming, or both sides when the caret is inside a conflict block.
- Open dialogs: ⌘O opens a native folder picker to open another project in a new window; an "Open File…" command opens any file in the current window.
- Source Control panel (⌘2): branch display, staged / unstaged / untracked file groups with stage, unstage, discard and stage-all; commit, push and pull.
- Editor zoom (
⌘=/⌘-/⌘0) and a soft word-wrap toggle (⌥Z). - Navigation history: go back (
⌃-) and forward (⌃⇧-) across jumps. - Richer status bar: git branch, line ending (LF/CRLF), indentation and encoding.
- Recent-files quick switcher (⌘E): a most-recently-used list of files opened this session, newest first, with arrow-key navigation.
- Built-in auto-updater: checks GitHub for newer releases on startup, shows the changelog in a notice, and installs the update in place on confirmation. Manual check available via the command palette ("Check for Updates").
- Release workflow that publishes per-platform binary assets for each tag.
- Find & Replace: replace and replace-all in the active file, with
case-sensitive, whole-word and regex toggles (
⌥⌘F). - Editing essentials: toggle line comment (
⌘/), go to line (⌃G), move line up/down (⌥↑/↓), duplicate line (⇧⌥↓), delete line (⌘⇧K), and indent/outdent (⌘]/⌘[). - Auto-closing brackets and quotes (with type-over and pair-aware backspace) and
auto-indent on newline. Configurable via
auto_close. - Unsaved-changes confirmation when closing a tab.
- External file-change detection: clean buffers reload automatically; buffers with unsaved edits show a reload/keep prompt.
0.1.0 - 2026-06-27
Added
- Tree-sitter syntax highlighting for Rust, Python, JavaScript, TypeScript, Go, C/C++, JSON, PHP, HTML, CSS, Blade, Vue and Svelte.
- Language Server Protocol client with diagnostics, completion, hover, go-to-definition, find references, document & workspace symbols, formatting, rename, code actions and signature help; per-language servers auto-selected.
- Laravel-aware completion for
route(),view(),config()andenv(). - Fuzzy file finder (
⌘P) and command palette (⌘⇧P). - Workspace search (
⌘⇧F) and find-in-file (⌘F). - Integrated PTY terminal with ANSI colour, multiple tabs, rename and split.
- AI agent panel (
⌘L) running configurable CLI agents (Elyra, Claude Code, Codex), with an agent selector and global settings. - Split editor, resizable panels (drag), multi-cursor (
⌘D). - Git change gutter and inline diff vs
HEAD. - Inline diagnostics, bracket matching, snippets, breadcrumbs.
- Markdown preview (
⌘⇧M). - Light/dark themes (
F8), auto-save, format & trim on save. - Session persistence per workspace and a workspace-wide problems panel.