-
Bugfix: TAB on an expandable block label no longer blocks the
<tab>->TABkey translation, extending the fix in #281 to the label'skeymaptext property, which outranks the mode map. It bound the raw<tab>event and shadowed layered keymaps binding onlyTAB; it now bindsTAB, which also makes the label's own binding reachable in terminal frames, where<tab>is never sent. -
Bugfix: chat block and table faces now follow theme switches (#301). The refresh was hooked buffer-locally on
enable-theme-functions, so it never ran (theme switches run the hook from the user's current buffer, not the chat buffer); it is now a global hook, withenable-theme/disable-themeadvice on Emacs < 29 where that hook doesn't exist. Expandable-blockline-prefixindentation also baked the resolved background color into the prefix strings; it now stores the face symbol, so already-rendered indentation updates on redisplay too. -
Show the summaries of tool calls pending approval in the inline prompt overlay status instead of the generic "Waiting for tool call approval" progress text (which overwrote the approval status), so it's clear what is about to run. With multiple pending tools, resolving one now keeps showing the remaining summaries, and approving from another client clears the stale approve/reject hints.
-
Bugfix: a region ending at the beginning of a line (whole-lines selection) no longer includes that extra line in the lines range sent by the
eca-chat-add-context-*commands, and ranges/cursor positions computed in narrowed buffers now use absolute file line numbers. -
Add
eca-chat-inline-prompt(transient menuI): ask ECA from any buffer, streaming the answer into a markdown-rendered scrollable overlay at point, backed by the serverchat/inlinePromptmethod. Picks the backing chat on first use (forking an existing one server-side or starting fresh), sticky per buffer,C-ure-asks; region/file attached as context,rreplies,a/danswer tool calls,mopens a menu to change inline model/variant/agent, open the backing chat or toggle overlays visibility (eca-chat-inline-toggle-overlays). Requires eca server withchat/inlinePromptsupport. -
Killing a chat buffer no longer asks about deleting the chat from the server: it just closes the buffer, leaving the chat resumable until the server retention cleanup removes it. Delete explicitly with
eca-chat-delete, the workspaces dashboardd, or the new server/delete-chatcommand. -
Add
eca-chat-compose(transient menui): compose a prompt in a dedicated markdown buffer instead of the inline chat prompt field, convenient for long or multi-line prompts.C-c C-csends the buffer content to the chat it was opened from (or the session's last used chat),C-c C-kdiscards it.@context/#filepathmentions complete against the ECA server, and yanking a clipboard image inserts an@filemention pointing at a saved screenshot, mirroring the chat buffer. -
Bugfix: Enter now works with transient/overriding keymaps that bind only
"RET"(e.g. Embark's action maps) inside chat buffers.eca-chat-mode-mapbound the raw<return>event, which blocked the<return>->RETkey translation in GUI frames, so those keymaps'RETbinding was never reached and the keypress silently fell through toeca-chat--key-pressed-returninstead; onlyRETis bound now. -
Restore the rolled-back user message into the prompt field.
Rollback chat to before this message(when messages are included) used to discard the clicked message's text together with the rest of the turn; the text now lands in the prompt unsent, ready to edit and resend, and any draft already typed in the prompt is kept below it, separated by a blank line. -
Fall back to the buffer's
xrefbackend (eglot, etags with a loaded tags table, any custom backend) foreditor/getDefinition/editor/getReferenceswhen lsp-mode cannot serve the file, instead of answering no-server.includeDeclaration: falseis honored by filtering definition locations out of the references, since LSP-backed xref backends always include the declaration. (editor-code-assistant/eca#351) -
Support
editor/getDefinitionandeditor/getReferencesserver requests via lsp-mode, letting the LLM navigate to a symbol definition/references using the editor's LSP. When no server is attached yet for a file of a known lsp project, lsp is started in background andstartingis answered so the eca server retries.startingis also answered while an attached workspace is still initializing, since lsp-mode would reject the request with a misleading "does not support method" capability error before the initialize handshake completes. Synchronous lsp-mode errors are answered aserrorresponses, and any server-request handler error now answers an error response instead of escaping into the process filter ("error in process filter" in Messages) and leaving the request pending until the server times it out (30s). Requires eca server with editor navigation support (editor-code-assistant/eca#351). -
Bugfix: a GitHub outage no longer prevents eca from starting. The release check now has a timeout and retries (
eca-server-fetch-timeout,eca-server-fetch-retries) instead of hanging Emacs, failed checks back off for 60s instead of re-blocking every start, and error payloads (e.g. rate limit) are no longer cached as a valid releases list. When an update download fails but a server is already installed, eca warns and starts the installed binary instead of not starting at all (also for errors in the asyncurl-retrievedownload, which were previously uncaught). -
Support adding a region of a non-file buffer (magit, vterm, compilation, the chat itself) as context with the
eca-chat-add-context-*commands: the selection becomes atextcontext with a lines range, its content sliced from the live buffer at prompt time. The commands now signal auser-errorinstead of silently doing nothing when no context applies. #294 -
Bugfix:
eca-chat-remove-workspace-rootfailed withWorkspace folder not foundfor a dir shown in the mode-line. Workspace dirs are matched withstring=, butC-u M-x ecastored them asread-directory-namereturned them (~/proj/) while add and remove expanded their argument, andexpand-file-namekeeps trailing slashes so/xand/x/never matched either. Dirs are now expanded and stripped of the trailing slash wherever they are stored or compared, which also stopsM-x ecaopening a second session for a root already held under a different spelling. -
Bugfix: shell command breakdown no longer stays yellow when the tool call was auto-approved (e.g. trust mode) or already ran; commands now show green once approved, keeping yellow only while approval is pending.
-
Turn
eca-workspacesinto a live dashboard: rows refresh automatically as chats change state, each chat showing status (⏳ running, 🚧 pending approval, ❓ waiting answer), elapsed time, cost and model, with workspaces sorted alphabetically. Actions on the entry at point, all listed in a transient menu (?): new chat with optional initial prompt (+), delete chat or stop workspace with confirmation (d/DEL), rename (r), fork (f), compact (C), select model/variant (m/v), accept/reject pending tool calls (a/A/x), stop prompt (s) and resume a closed chat (R). -
Bugfix: quitting the delete-chat prompt (
C-g) now really cancels the kill instead of leaving the chat alive but orphaned, without a window, tab or registry entry. Quitting it duringeca-chat-resetleaves the session untouched as well, instead of adding a replacement chat next to the one that survived. The answered prompt no longer lingers in the echo area.
-
Bugfix: restore the status colors of the
mcps:counts in the chat header-line, lost in #288 which overrode the per-status faces witheca-chat-option-value-face; that face is now merged with lower priority so both apply. -
Bugfix: cursor context no longer shows as
@cursor( :)when no position was tracked yet. Tracking now picks the most recent file buffer inside a workspace (instead of bailing when the newest file buffer is external), the chip shows@cursor(no file)until a position exists, and at prompt send the position is computed as a last resort, dropping the cursor context instead of sending it with empty path/position. -
Bugfix: stop Emacs stuttering while ECA runs and a buffer of another project is visited. The cursor-tracking idle timer resolved the session via
eca-sessionfrom whatever buffer was current; for buffers outside any session that resolution is never cached, so every idle tick probed project.el and shelled outgit rev-parse --git-common-dir(once for the buffer root plus once per session workspace folder). The timer now matches the last visited file buffer against the sessions' workspace folders in memory, andeca--git-common-dircaches its results (cleared on session create/delete) and runs git viaprocess-filewithout an intermediate shell. #275 -
Bugfix: server auto-update was permanently disabled when the version file (
eca-server-version-file-path) was missing (e.g. after an interrupted update): the nil version made the up-to-date check always pass, andeca-server-check-updatesmisreported it as not installed. A missing version file now triggers a reinstall on start, the updater only writes the version file on success instead of deleting it upfront, startup uses the installed binary when the release check fails (offline), andeca-uninstall-serverremoves the version file too. -
Bugfix: prevent
(invalid-function #<symbol json-parse-buffer ...>)on Emacs 31 when fetching releases or parsing server messages.eca-api--json-read-bufferexpanded to a shared literal form that the byte-compiler can mutate in place (macroexp--posify-form-1), poisoning later runtime expansions; the macro now conses a fresh form on each expansion. #284 -
Bugfix: don't crash with
wrong-type-argument number-or-marker-p nilonchat/statusChangedidle when the chat buffer lost its prompt-block overlays.eca-chat--content-insertion-pointand the table align/beautify end bound now fall back topoint-maxinstead of(1- nil), andeca-chat--refresh-progressskips when the progress overlay is missing. #283 -
Bugfix: stop the chat view jumping up and down while the LLM streams small chunks (e.g. preparing tool calls). Chat buffers now set
scroll-conservatively/scroll-marginbuffer-locally so redisplay scrolls line by line instead of recentering (the jumping depended on the user's global scroll settings). Also reduce streaming redisplay churn: the progress spinner keeps a fixed width, the progress area only re-renders when its text changes, and unchanged tool-call labels skip their delete/re-insert. #268 -
Support adding non-file buffers (compile, comint, etc.) as chat context:
@completion now offers eligible buffer names, sent astextcontexts with fresh content captured at prompt time, and theeca-chat-add-context-*commands work from non-file buffers. Customize candidates witheca-chat-context-buffer-predicateand size witheca-chat-context-buffer-max-chars. Requires eca server withtextcontext support. #278 -
Add current-window chat display: set
eca-chat-window-sideto nil to open a new chat in the selected window without creating a split. This takes precedence overeca-chat-use-side-windowand does not replace another chat visible in a different window on the selected frame. -
Bugfix: auto-scroll the chat so the prompt stays visible after sending a long message. Rendering the sent user message pushed the prompt below the window end, which also made the guarded auto-scroll a no-op (its window-end check runs after the insertion, so it always failed for long messages); the send path now forces the scroll, skipped when prepending older history pages. #279
-
Make the
eca-workspacestree buffer more user-friendly. It now uses a dedicatedeca-workspaces-mode(derived fromspecial-mode), soqcloses the window andgrefreshes. Folding/unfolding a workspace no longer requires hitting the small arrow icon: pressingTAB/RETon its line toggles it, and pressingRETanywhere on a chat line switches to that chat.n/pmove to the next/previous workspace entry. Wheneca-buttons-allow-mouseis enabled, clicking the workspace text folds/unfolds it and clicking a chat switches to it. -
Add
eca-mcp-toggle-server, available asMin the ECA transient menu andC-c C-S-min chat buffers, to filter configured MCP servers and start, stop, or connect the selected server from aligned, color-coded operational-state candidates. -
Bugfix: TAB now accepts the selected candidate in completion popups (corfu) in GUI Emacs.
eca-chat-mode-mapbound the raw<tab>event, which blocked the<tab>->TABkey translation and shadowed the completion UI's ownTABbinding, restarting the completion session instead; onlyTABis bound now, so keymap precedence decides while a popup is open. #281 -
Bugfix: a forward deletion of the first prompt character now works instead of dinging.
eca-chat--key-pressed-deletionguarded the prompt boundary by rejecting any deletion at the prompt-field start regardless of direction, soC-dand, under evil, the~(evil-invert-char),r,xandsoperators left the first char in place (~prepended the inverted char instead of replacing it). At the prompt-field start the guard now blocks only backward-deleting commands (delete-backward-char,backward-kill-word,evil-delete-backward-char, ...); deletions above the prompt (context/progress area) and everywhere else are unchanged. -
Show the shell/git command breakdown in tool call approvals: raw command plus per-command lines colored by remember state (green saved, yellow not yet), and
Accept and rememberlists the command keys it would newly save (e.g.git status, rg), hiding when nothing new would be remembered. -
Support TRAMP / remote hosts: the eca server starts on the remote host, the binary is resolved from the remote
PATH, and paths are translated both ways using mappings derived from TRAMP workspace folders (expliciteca-local-to-remote-prefix-mapentries win). Auto-install is local only: installecaon the remote or pointeca-custom-commandat it. #270 -
Improve chat
@/#completion: selecting a directory now drills into it (keeps completing its contents) instead of finalizing; candidates are workspace-relative paths with directories ending in/; candidates no longer vanish mid-token depending on the user'scompletion-styles; TAB in the prompt triggers completion for@/#//tokens; typing a space after a raw@pathturns it into a context chip and raw@pathtokens still count as contexts when the prompt is sent. -
Respect
eca-chat-window-side(and width/height) even wheneca-chat-use-side-windowis nil, displaying the chat on that side viadisplay-buffer-in-direction. To avoid overlapping/duplicate windows, placement now reuses the window already showing the chat, otherwise replaces another visible chat window in place (new-tab behavior), and only opens a new window when there is nothing to reuse. -
Bugfix:
eca-chat-add-context-to-user-promptandeca-chat-add-filepath-to-user-promptno longer error withwindow-live-p, nilwhen the chat buffer is not visible; the chat window is now displayed first. With a prefix arg (C-u) they add the context without selecting the chat window, leaving point where it was. #266 -
Add
eca-chat-hide-markdown-markup, an opt-in display control for users seeing fenced code blocks jump in chat buffers. The default preserves the existing hidden-markup rendering; set it tonilto keep markdown fences/backticks visible, which avoids markdown-mode's fenced-code boundary invisibility during typing and streaming. -
Bugfix: don't move the cursor while the chat is streaming.
eca-chat-content-receivedrendered without asave-excursion, so content streamed above the prompt (e.g. while "thinking") dragged point up to the middle of the buffer; point is now preserved. -
Bugfix: keep the
:usageand:trustmode-line segments visible after adding the context-usage bar. The right-alignment reserved space from(length right), which counts the bar's pixel-widthdisplayspaces (and wide glyphs) as ~1 char each, so the segments overflowed off the right edge. It now measures the real rendered width viastring-pixel-widthand aligns flush to the right edge in pixels (Emacs 29+ only; on Emacs 28 right segments follow left without alignment). -
Bugfix: closing a chat (
kill-buffer,C-c C-k, or the tab close button) now switches the chat window to a sibling chat (the previous tab, or the only one left) instead of falling back to an unrelated buffer like the settings buffer, and drops the dead chat from the session registry.C-c C-k(eca-chat-reset) only starts a fresh chat when the closed chat was the last one. -
Add
eca-chat-copy-at-point, bound toC-c C-w. It copies the fenced code block at point, the assistant response at point, or the latest response as a fallback. -
Bugfix: guard
chat/askQuestionagainst a non-sequence:options(e.g. a malformed string from a misbehaving server).appendwas splitting such a string into character integers that rendered as a list of random numbers; non-sequence options are now treated as empty. -
Add a context-usage bar in the chat mode-line, left of the token usage, showing how full the model context window is, colored by category (system prompt, rules, skills, AGENTS.md, tool definitions, tool calls, conversation, free space), each a distinct color. In graphical frames it renders pixel-width thin segments for high granularity (small percentages stay visible); terminals fall back to block characters. Same footprint either way (
eca-chat-context-bar-width). Colors come from the server (canonicalcolor/freeColor) so they are consistent; hover the bar for a legend that maps each category to its server emoji swatch (emoji/freeEmoji, matching the/contextcommand output), or click to run the new/contextcommand. Configurable viaeca-chat-context-bar-widthand the:context-barmodule ineca-chat-mode-line-format. Needs an eca server that sendscontextBreakdowninusagecontent. -
Auto-dismiss a pending
ask_userquestion when another client (e.g. an SSE/web client in remote mode, see eca 0.139.0) answers it first. The server resolves theask_usertool out from under us and sends atoolCalled/toolCallRejectedfor that tool-call id but no longer expects our answer (it cancels our request); we now correlate that id witheca-chat--pending-questionand clear the stale answer-mode prompt state instead of staying stuck waiting for input. -
Paginate long chats instead of replaying the full history on open. With
eca-chat-history-page-sizenon-nil (default 50),eca-chat-resumeopens a chat with only the newest page and shows a clickable "Load older messages" control at the top to page through earlier history on demand via the newchat/historyrequest (also bound toC-c C-S-o). Older pages are prepended above the existing content, reusing the streaming renderer (subagent nesting included) and kept read-only like the rest of the history. Seteca-chat-history-page-sizeto nil to keep the previous full-replay behavior. -
Bugfix: resuming a previous session after a server restart no longer reopens it as a
*Closed session*(mode-line) /This chat is closedbuffer that rejects new prompts.eca-chat-exit(run on restart) marks the most-recent chat buffereca-chat--closedbut leaves it in the session registry;eca-chat-openedwas treating that live-but-closed buffer as "already known" and replaying the resumed history into it. It now treats a registered buffer markedeca-chat--closedas stale, killing the leftover closed buffer and creating a fresh, writable one in its place. -
Color the Doom Emacs workspace tabline by ECA session status: orange when a chat waits for approval/question, dim yellow while running. Enabled automatically on Doom (
:ui workspacesmodule), disable witheca-doom-workspace-tabs. -
Bugfix: keep the Doom workspace tab colors in sync with the real status. The tabline was only recomputed on workspace switch /
+workspace/display, so a shown tabline went stale: a tab could stay white after its prompt started, or keep the running color after it finished. Status transitions (chat start/finish, approval/question shown or answered) now refresh the tabline while it is the message on screen, and a chat that is onlystoppingno longer counts as running. -
Add
eca-chat-go-to-next-attentionandeca-chat-go-to-next-attention-in-projectcommands to jump to the next chat waiting on the user (pending tool call approval or unanswered question), cycling across all sessions or only the current one. -
Make the chat history/output, the
---separator and the task area read-only so only the progress,@-context and prompt input lines stay editable, preventing accidental edits to previous messages and assistant output. Theread-onlytext property is applied up to the progress area (with stickiness tuned so typing still works) and kept in sync as content streams in and as blocks are expanded. Toggle off via the neweca-chat-read-only-history(defaultt). -
Add
eca-table-opento view a markdown table at point in a dedicated*eca-table*buffer withtruncate-lines, so wide tables can be scrolled horizontally with the header staying aligned and the whole table searched/copied. Pressowith point on any table to open it, or click[o] openon a wide table's action bar. Theobinding lives in a char-property keymap scoped to the table, so it takes precedence overoonly while point is on a table (works under evil) and leavesountouched elsewhere. The in-chat table rendering is otherwise unchanged. -
Add
eca-chat-deletecommand to delete the active chat from the server without prompting. Works from any buffer in the project (acts on the session's last visited chat), switches the chat window to another chat first when one exists, and is bound toC-c C-S-kplus aDeleteentry in the transient menu. -
Bugfix: pressing
RETon a URL in the chat now opens it even when the URL is wrapped in markdown emphasis like**https://...**or_https://..._. The face at point is a list in that case, so the oldeqcheck missed it; the trailing**/_markers are also stripped so the right URL opens. Proper[text](url)links still go throughmarkdown-follow-thing-at-point. -
Bugfix: switching chat tabs via
tab-line-switch-to-next-tab/tab-line-switch-to-prev-tabor clicking a tab now switches the chat in place instead of opening it in a new window. -
Bugfix: trigger
@/#chat completion even when a char like(immediately precedes it. -
Bugfix: don't crash with
(wrong-type-argument stringp nil)whenchat/askQuestionsends options as plain strings or option objects without a:label. Options are normalized viaeca-chat--normalize-question-option(string or plist) and the label always falls back to a non-nil string. -
Bugfix: keep the
stopbutton available while a question is pending. A pending question keeps the turn active server-side even when the chat reports idle, so the loading/stop transient segment andeca-chat--stop-promptnow treat a pending question like the loading state, and the transient area is refreshed when a question is shown/answered/cancelled. -
Bugfix: clear the chat progress text and spinner when
chat/contentReceivedprogress/finishedarrives whileeca-chat--chat-loadingis nil (e.g. after the 10s stopping safety-timer reset the flag, or for server-driven progress not started viaeca-chat--send-prompt). The wildcardpcasearm added in 19aa392 to ignore stale duplicatefinishedevents was dropping the visible UI cleanup too; it now still clears progress text, spinner and elapsed timers idempotently while skipping the trailing newline / fontify / queued-prompt dispatch so duplicatefinishedevents remain harmless. -
Bugfix:
eca-chat-resumeno longer silently no-ops when the picker is shown from a fresh welcome buffer. Filter out chats the server can't open (id is nil, which happens for legacy DB rows that pre-date the per-chat:idfield) so they aren't offered, and surface auser-errorwhenchat/openreports:found? falseor no buffer was registered for the chat-id, instead of falling through thewhen-let*. -
Add
eca-chat-resumecommand to pick and resume a past chat viacompleting-readannotated with model, message count and relative update time. AResume a previous sessionlink in the welcome area triggers it, andeselects it in the transient menu. The originating empty welcome buffer is killed once the resumed chat is in place, so no stray tab is left behind. -
Bugfix: avoid
(wrong-number-of-arguments color-rgb-to-hsl 0)crash on chat startup in a no-window/TTY Emacs.face-backgroundreturns the literal sentinel"unspecified-bg"(not nil) on non-graphic frames, which was fed intocolor-lighten-name/color-darken-namefromeca-chat--update-expandable-block-facesandeca-table-update-faces. Neweca-safe-face-backgroundhelper ineca-util.elnormalizes the"unspecified-bg"/"unspecified-fg"sentinels to nil so thewhen-let*guards short-circuit and the faces remain at their default appearance on TTY. #244 -
Add inline
[+ Add MCP server]form and per-rowremovebutton (with two-step inline confirmation) on the MCPs settings tab. Handles the newtool/serverRemovednotification so the UI updates live without a server restart. -
eca-doctornow emits a### Self-checksection probing whether the loaded code carries the chat-RET expand fix:eca-chat-mode-mapRET still points ateca-chat--key-pressed-return,eca-chat--key-pressed-returnreferences the expandable clause before the markdown-link clause, the nearest expandable block label has RET bound in its text-propertykeymap, and the loadedeca-chat-expandablefile's path (with a stale-.elcwarning when the on-disk.elis newer). Each failing probe pushes a targeted hint pointing at commitdac33d8and the appropriate remediation (pull master, restart Emacs,M-x byte-recompile-directory, or start a new chat so blocks get the new label keymap). -
Bugfix: restore RET expanding/collapsing
>blocks in the chat. The recent markdown-link-on-RET clause was intercepting the toggle when the label text was fontified as a link; the expandable check now runs before the link follow, and the label's text-property keymap also binds RET so it works in evil normal state without evil-collection wiring. -
Add
eca-doctorcommand that prints a markdown-formatted diagnostic report to*eca-doctor*for bug reports: a## Versionssection (same aseca-version) plus a## Chatsection sourced from the active session's auto-detected chat buffer. #242 -
Bugfix: stop the
mergedworktree fallback ineca-sessionfrom auto-adding an unrelated ancestor (typically$HOME) as a second workspace folder. The fallback previously declared two paths to be the "same repo" purely ongit rev-parse --git-common-direquality, which is also true for any subdirectory of a git-tracked HOME (yadm/chezmoi/git init ~); a buffer whosedefault-directoryis~(e.g. the doom scratch buffer) would then triggerworkspace/didChangeWorkspaceFoldersand append~to the session created withC-u M-x ecaon~/.config/eca, showing both roots in the chat modeline. The match ineca--session-for-worktreenow additionally requires that ROOT and the candidate folder are not in an ancestor/descendant relationship (real worktrees are always sibling directories, never nested), via the neweca--paths-nested-phelper. True sibling worktrees continue to merge as before. #238 -
Generate
chatIdclient-side at chat-buffer creation. #231 -
Scope model/agent/variant selection to the active chat:
eca-chat-select-model,eca-chat-select-variantandeca-chat--set-agentnow write the local change to the chat buffer the user is interacting with (current buffer when invoked from inside a chat, falling back to the session's last chat) and include:chatIdin the resultingchat/selectedModelChanged/chat/selectedAgentChangednotification.eca-chat-config-updatedhonors the newchatIdfield onconfig/updated: when present, per-chat fields (selectModel,selectAgent,selectVariant,selectTrust) apply only to that chat's buffer; when absent, the legacy session-wide path applies to every chat (still used for the initialconfig/updatedafterinitialize). Fixes a long-standing leak where changing the model in one chat would silently overwrite another chat's display. #231 -
Add
eca-process-wrapper-function, an optional function called with the resolved server command and the list of workspace folder paths just beforemake-processis invoked. It must return a (possibly transformed) command list, letting users run the eca server inside any command-prefix-style sandbox (firejail, bubblewrap, jai, docker, ...) directly from elisp — without a separate launcher script and with the workspace roots dynamically injected into the sandbox's directory whitelist. New "Sandboxing" section in the README documents the recommended pattern withjaiandfirejailexamples. -
Expand the
eca-send-process-iddocstring to explicitly cover sandbox tools that hide or remap the host PID (firejail, bubblewrap, jai, containers): in those setups the server's parent-process watchdog would otherwise see an invalid PID and shut down right after startup, so the variable must be set to nil. Cross-referenceseca-process-wrapper-function. -
Bugfix: avoid
void-function flymake-diagnostic-codeerrors ineca-editor--flymake-diagnostics(which surfaced as a 30sTimeout waiting for editor diagnostics responseoneditor/getDiagnosticswhenever any flymake diagnostic was processed) byfboundp-guarding theflymake-diagnostic-codeaccessor;:codeis simply omitted when the accessor isn't shipped with the running Emacs'sflymake. The existingdeclare-functionis preserved so the byte-compiler stays quiet on Emacsen that do expose it. #228 -
Hide the
[-](remove workspace) mode-line button when only a single workspace folder is active in the session, since removing the last workspace is disallowed anyway; the[+](add workspace) button is still always shown. The button reappears automatically as soon as a second workspace is added. -
Stop the CPU peg when watching a long uncollapsed write-tool argument body stream in (#234). The dominant cost was
gfm-mode's markdown matchers (markdown-match-italic/markdown-match-bold/markdown-match-code) re-fontifying the whole growing body on every chunk, becausetoolCallPrepareupdates go througheca-chat--update-expandable-content'sdelete-region+ reinsert branch (which marks the entire body as needing fontification and lets jit-lock then run the matchers over it on the next redisplay). Introduce a buffer-local customfont-lock-fontify-region-function(eca-chat--fontify-region) that walks the requested region ineca-no-fontifytext-property runs and only delegates the un-tagged sub-ranges tofont-lock-default-fontify-region; tagged sub-ranges are skipped entirely, so jit-lock has nothing to do on them. ThetoolCallPreparearm now tags the streaming body witheca-no-fontifyat the source string, which travels naturally through(propertize content 'line-prefix ...)insideeca-chat--update-expandable-contentand through the toggle-open path'seca-chat--insert, so every code path that lands the body in the buffer carries the tag. Cleanup is automatic: whentoolCalledarrives it reinserts un-tagged final content via the samedelete-region+ reinsert path, after-change-functions clearfontified, and jit-lock then refontifies normally on the next redisplay (no manualfont-lock-flushneeded). Measured via a newtool-prep-stream-{skip,full}benchmark inbenchmarks/eca-chat-bench.el(synchronous fontify per chunk to simulate jit-lock under--batch): at body 1000/5000/20000 chars, per-chunk cost drops from ~4.5ms / ~62ms / ~908ms to ~173µs / ~144µs / ~225µs respectively (26× / 432× / 4030×). The post-fix path is FLAT in body size (only the existing buffer churn remains), and the 20000-char run drops from 265 GCs to 0. -
Make long chats fast again. Replaced linear
(overlays-in (point-min) (point-max))scans in singleton-overlay accessors and the expandable-block id lookup with O(1) buffer-local caches (a per-overlay slot for the chat singletons; a per-buffer hash table for expandable blocks). Region-scoped the per-turnfont-lock-ensureand end-of-streameca-chat--align-tables/eca-chat--beautify-tablesto start ateca-chat--last-user-message-posinstead ofpoint-min, so cost is bounded by the current turn rather than the full chat history. Measured on a synthetic 500-turn fixture (benchmarks/eca-chat-bench.el): per-streamed-chunk insert dropped from ~426µs to ~6µs (71×), expandable-id lookup from ~324µs to ~0.4µs (790×), and the end-of-stream finalize block from ~2.6s to ~9ms (274×). -
Add
benchmarks/eca-chat-bench.el, a chat-rendering benchmark harness runnable viaM-x eca-chat-bench-runoreask emacs --batch -l benchmarks/eca-chat-bench.el -f eca-chat-bench-run. Builds synthetic chat buffers of varying size and times the streaming hot paths (insertion-point lookup, streamed chunk insert, expandable lookup/update, end-of-stream finalize); prints a markdown table with per-call µs / wall-ms / GC counts so future changes can be validated quantitatively. -
Bugfix: avoid corrupted redisplay in
emacs -nwby using single-cell BMP glyphs (●/○) for the chat mode-line trust indicator on terminal frames; emoji defaults are preserved on graphic frames. Configurable viaeca-chat-trust-on-symbol-tty/eca-chat-trust-off-symbol-tty. #229 -
Expire the cached GitHub releases list used for eca server update detection. Previously
eca-process--releases-cachewas populated once per Emacs session and never invalidated, so long-running Emacs instances never noticed new eca server releases (andeca-install-server, despite its docstring, was bound by the same stale cache). Neweca-server-releases-cache-ttldefcustom (default 3600 seconds;nildisables expiry;0always refetches) refreshes the cache on access once expired. New autoloaded interactive commandeca-server-check-updatesclears the cache and reports whether the installed server is up to date, has an available upgrade, or whether the GitHub check failed.eca-install-servernow also clears the cache before fetching the latest version, matching its "Force download the latest eca server." docstring. #230 -
Render assistant-emitted
ChatImageContentfromchat/contentReceivedinline in the chat buffer (e.g. images returned by the OpenAIimage_generationtool). Decodes the base64 payload and displays it via an overlay carryingcreate-imagedata (overlay rather thandisplaytext-property somarkdown-mode/gfm-modefont-lock cannot strip it onfont-lock-ensure), falling back to a[Image: <mediaType>, <N> bytes]placeholder on TTY frames or when the image type is unavailable in the current Emacs build. Sizing is configurable viaeca-chat-image-max-width(defaultfit-window— scales to the chat window body width, hard-capped byeca-chat-image-window-fit-cap, default 800px) andeca-chat-image-max-height(defaultnil); a fixed integer ornil(unconstrained) are also accepted foreca-chat-image-max-width. Per-chat zoom:eca-chat-image-zoom-in(C-c C-z +/C-c C-z =),eca-chat-image-zoom-out(C-c C-z -), andeca-chat-image-zoom-reset(C-c C-z 0) mutate the buffer-localeca-chat-image-scale(multiplier on the resolved width cap, default1.0) byeca-chat-image-scale-step(default1.2) and re-rasterize already-rendered images viaimage-flushso existing images snap to the new size without re-fetching. Save inline images to disk viaeca-chat-save-image-at-point(C-c C-z s), also reachable viaRETormouse-2directly on the image overlay (with a tooltip describing media type / byte count), with the destination customizable viaeca-chat-save-image-directory(defaultworkspace-root, resolving to<root>/.eca/images/; also accepts a literal path string ornilfordefault-directory) andeca-chat-save-image-filename-format(defaulteca-image-<YYYYMMDD-HHMMSS>.<ext>); saved bytes are pulled directly from the existing overlay viaimage-property :data, so display zoom does not affect the file and no server round-trip is needed. -
Syntax-highlight the inline
eca-completeghost-text overlay using the buffer'smajor-mode, with optional foreground dimming for a "ghost" look similar to Cursor / Copilot. Configurable viaeca-completion-syntax-highlight(defaultt) andeca-completion-overlay-dim-ratio(default0.5,nildisables dimming).eca-completion-overlay-facenow composes with APPEND priority on top of font-lock faces instead of overriding them. #227 -
Sync the mode-line trust indicator on chat resume by honoring the new
selectTrustfield onconfig/updated: the shield/flame icon now matches the server's persisted trust state for the resumed chat instead of always defaulting to off (eca #426). -
Defer fontification during chat streaming: replace the per-chunk
font-lock-ensurewith a debounced idle-timer scheduler plus a single guaranteedfont-lock-ensureat end-of-stream, configurable viaeca-chat-fontify-debounce-interval(default 0.15s,nildisables intermediate fontify). Cuts font-lock CPU by ~99% on fast-streaming models and ~84% on slow-streaming ones. -
Improve mode-line trust indicator: 🔥 (fire) when ON, 🛡 (shield) when OFF. Customizable via
eca-chat-trust-on-symbol/eca-chat-trust-off-symbol. -
Add
eca-chat-remove-workspace-rootcommand and[-]mode-line button to remove a workspace folder from a running session. Both 'add' and 'remove' is in the transient menu (W a/W r). -
Add
eca-chat-mode-line-formatfor customizable chat mode line layout. #184 -
Fix top-level
(require 'tab-line)causing side effects wheneca-chat-tab-lineis nil. #195 -
Add support for
chat/openedserver notification, enabling the/forkcommand to open forked chats as new tabs. -
Fix
eca--uri-to-pathreturning wrong path on Windows (leading slash before drive letter). #200 -
Add
eca-settings-tab-lineoption to disabletab-line-modein settings buffers. #201 -
Replace
helpful-headingface dependency witheca-settings-headingdefface. #201 -
Fix settings tab re-registration reordering tabs. #201
-
Add support for
chat/askQuestionserver request, enabling tools to ask users questions with selectable options in the chat buffer. #338
- Add
eca-chat-save-to-filecommand. #95 - Fix chat not being closed. #89
- Fix: check existing eca sessions when opening chat. #88
- Add rewrite feature.
- Fix issue with
view_ediffdisplaying empty buffers in ediff. #86 - Fix user message contexts and file paths not being sent. #112