Files
finrod/CHANGELOG.md
João Pedro Battistella Nadas 73aa54d7bd fix: Firefox clipboard, flip dropdown default to normal mode
- Replace Vim.map("...", "\"+...", ...) with custom Vim.defineAction
  handlers calling navigator.clipboard directly. The library's "+"
  register implementation doesn't reliably write on Firefox.
  Limitation: only yy/Y/visual-y reach system clipboard; bare
  y<motion> still uses vim's internal register.
- Flip dropdown modal: default NORMAL (j/k arrows), `/` or `i`
  enters search. Listener moved to document capture phase so closed
  dropdowns receive keydown on Firefox.
2026-06-09 16:53:11 +02:00

3.8 KiB

Changelog

All notable changes to finrod are documented here.

Format: Keep a Changelog. Versioning: Semantic Versioning.

[Unreleased]

Added

  • Vim bindings in the input via CodeMirror 6 + @replit/codemirror-vim (loaded from esm.sh, no build step). Supports i/Esc, hjkl, word/line motions, dd/yy/p, undo/redo, / search, : command line. Auto-disabled on touch devices (detected via (pointer: coarse)) where modal editing fights the virtual keyboard.
  • Shift-H / Shift-L cycle focus across the page controls (source → target → model → editor → button) like Shift-Tab / Tab. Also overridden in vim normal mode (replacing vim's viewport-top/bottom default) so the same shortcut works to leave the editor.
  • yy / Y and visual-mode y in the editor copy to the system clipboard via custom navigator.clipboard.writeText() actions (the library's + register is broken on Firefox). Bare y<motion> (e.g. yw, y$) still uses vim's internal register — that path would need a deeper hook into the library's register system.
  • p / P in vim normal mode paste from the system clipboard at / before the cursor via navigator.clipboard.readText(). Browsers may show a one-time permission prompt or chip; granting clipboard-read for the origin makes future calls silent. On Firefox, ensure dom.events.asyncClipboard.readText is true (default in recent versions) or the read will be blocked.
  • Vim-style modal navigation on the From / To / Model dropdowns (default NORMAL):
    • j / k move selectedIndex down / up (works whether the dropdown is open or collapsed; uses document-level capture-phase listener so Firefox plays along)
    • / or i enters search mode — letter keys then do native typeahead; accent-coloured border indicates it
    • Esc returns to normal mode; blur also resets so the next focus starts in normal
  • On page load, the model dropdown defaults to whichever model Ollama already has hot — skips the 5-15 s disk-reload pain on the first translation. After load it follows the user's manual selection.

Changed

  • Editor font-size pinned to 1rem to match the output pane (CodeMirror 6 ships smaller by default).

[0.1.0] - 2026-06-09

First release. Stateless translator UI that proxies streaming requests to Ollama on radagast.

Added

  • FastAPI backend with three endpoints:
    • GET /api/models — filtered (gemma,aya by default) list from Ollama's /api/tags
    • POST /api/translate — streams Ollama's NDJSON /api/generate response back to the browser
    • GET /api/loaded — proxies Ollama's /api/ps for the currently-loaded model
    • GET /healthz — for Kubernetes probes
  • Single-page UI:
    • Source / target / model dropdowns (30+ languages, "Auto-detect" source)
    • Token-by-token streaming into the output pane with a blinking caret
    • Live status line: spinner while waiting for first token, pulsing dot during streaming, elapsed time and token count
    • Glowing border on the output pane during streaming
    • Loaded-model indicator ( prefix in dropdown, "Hot: … — unloads in Xm" status line); refreshes on page load, on translation completion, and 500 ms after typing pauses
    • ⌘/Ctrl-Enter to translate from the input
    • Dark mode, inline SVG favicon (Star of Fëanor)
  • Dockerfile: two-stage uv build, slim Python 3.13 runtime
  • build.sh: multi-arch (amd64 + arm64) manual push to Scaleway, tags :latest, :<git-short-sha>, and :<pyproject-version>
  • Cluster deploy via the valinor repo at apps/finrod/ (bjw-s app-template, internal-only ingress at finrod.jpnadas.xyz)

Fixed

  • Lock against public PyPI explicitly — the workstation's global uv config had pointed uv.lock sources at the dexterenergy private artifact registry, which 401'd inside Docker