- y/Y/yy and visual y now route through vim's "+" register, which
copies to the system clipboard via the synchronous document
.execCommand("copy") path — no permission prompt.
- p/P also remapped to "+ register for symmetry; replaces my custom
navigator.clipboard.readText() action. Browser may still show a
permission chip on first paste; granting once makes it silent.
- Source / target / model dropdowns get modal vim-style nav:
default is native typeahead, Esc → normal mode (accent border),
j/k move selectedIndex, i and / return to search, blur resets.
Disabled on coarse-pointer devices.
3.5 KiB
3.5 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). Supportsi/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-Lcycle focus across the page controls (source → target → model → editor → button) likeShift-Tab/Tab. Also overridden in vim normal mode (replacing vim's viewport-top/bottom default) so the same shortcut works to leave the editor.y/Y/yyand visual-modeyin the editor now copy to the system clipboard via vim's+register (synchronousdocument.execCommand("copy")under the hood — no permission prompt).p/Pin vim normal mode paste from the system clipboard at / before the cursor via the same+register. The first paste may show a one-time browser permission chip; granting clipboard-read on the origin makes future calls silent.- Vim-style modal navigation on the From / To / Model dropdowns:
- Default is native typeahead search (type letters to filter)
Escenters normal mode; an accent-coloured border indicates this- In normal mode,
j/kmove selectedIndex down / up ior/returns to search mode; blur also resets so the next focus starts in search
- 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
1remto 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,ayaby default) list from Ollama's/api/tagsPOST /api/translate— streams Ollama's NDJSON/api/generateresponse back to the browserGET /api/loaded— proxies Ollama's/api/psfor the currently-loaded modelGET /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
uvbuild, 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
valinorrepo atapps/finrod/(bjw-s app-template, internal-only ingress atfinrod.jpnadas.xyz)
Fixed
- Lock against public PyPI explicitly — the workstation's global
uvconfig had pointeduv.locksources at the dexterenergy private artifact registry, which 401'd inside Docker