v1.3.230
Release v1.3.230
Note: the v1.3.229 tag was cut from a tree whose desktop release matrix
could not build (details below under "Release Pipeline"); its Release
workflow failed and no 229 artifacts were published. This release carries
the same content plus the pipeline fixes. Mobile 1.3.229 (versionCode
2026090101) did ship and is functionally covered by these notes.
CJK / Input Correctness
- c766e68: long CJK drafts restored into the composer no longer render
with the tail clipped — the classic "Chinese chars vanish from the input
box but appear when sent" bug.composerCursorEndnow syncs the viewport
(View()) beforeMoveToEnd(), because the textarea's internal
repositionView clamps its scroll against the previous content; CJK hits
this fast since soft-wrap fits only ~7 full-width runes per line at
narrow widths. History recall (Up arrow) follows the same path now. - f03e5bb: web_fetch truncates by runes, not bytes — no more mojibake
when fetched pages are capped (also stops double-cloning the transport) - 369096e: url_expand no longer swallows CJK characters and keeps
balanced parentheses - 2882f0b: hooks panel accepts CJK input with rune-safe backspace;
save errors are visible
TUI Fixes
- #1391: shell completion no longer wipes agent cancel state; no shell
re-entry after completion - #1385: first-install onboarding — no sentinel model, no stale
discovery, no stuck spinner - #1389: stdout probe writes real bytes; loadSession acquires the new
lock before releasing the old one - #1365: failed @mentions stay in the message instead of vanishing
- #1381: lanchat
#reply routes to the sender; send errors visible - #1362: lanchat DM/broadcast send failures surface instead of fake
success - #1379: IM runtime failure no longer masquerades as success;
impersonate delete persists - #1364: knight adhoc tasks cancelled on exit — no post-exit LLM billing
- #1363:
/knight approveglobal skills requires--confirm-global - #1361: shortenPath requires real path boundaries for prefix matches;
escape check usesos.PathSeparator - #1366:
/diffoff the event loop with timeout;/diff <file>stat
keeps the path;/costreads under session lock - #1390: Ctrl+R sidebar toggle syncs all panels like handleResize
- #1360: identical todo_write after
/clearrebuilds the chat card - #1388: memory reflection reads only its own key — no cross-memory
pollution
TUI i18n
- #1372: ja catalog falls back to enCatalog; format verbs match call sites
- #1373: ko catalog restores format verbs;
help.texttranslated - #1376: zh model-panel error keys; wechat/whatsapp
no_botkeys - #1374: QQ panel actions hint shows d/e/q keys in all 10 languages
- #1375: Signal/Twitch QR flow feedback — silent paths now speak
Tool Fixes
- #1358: write_file records its own writes — no more stale misreport
- #1356: ExitWorktree
--forceonly when discard_changes authorized - #1357: web_search allowed_domains exempt from per-domain dedup cap
- #1352: DDG result-block regex no longer over-matches structural wrappers
- #1349: wait_agent
wait_secondscapped at 30 minutes like sleep - #1359: AtomicWriteFile resolves symlinks — writes the real target,
keeps the link - #1348: warp keystroke failures propagate; ctx threaded through the
osascript chain
Tunnel / Relay / Desktop
- #1354: relay resume supersedes the old connection; acks validated for
ownership and monotonicity — fixes double delivery on mobile network
switches - #1400: tunnel projection cache no longer evicted on save failure; relay
local-host heuristic explicit - #1401: replay comparator strict weak ordering; compact-qualified
remaining key - #1350: trayhelper built into desktop bundles — tray was dead in production
- #1351: tray shutdown race closed — no ghost icon or orphan helper
- #1403: tray helper spawn under lock, respawn backoff, listener closed
on teardown - #1355: matrix GetHistoryVisibility fails closed on state fetch errors
- #1399: wecom create persists IM.Enabled — bot no longer vanishes after
restart - #1369: extpane iterm2 probe timeout; transient failures retry instead
of permanent dark - #1368: extpane compactPreview normalizes before truncating
CI / Infrastructure
- df8aa1d: the Format job no longer poisons the shared setup-go module
cache with an empty stub (immutable per key), which forced every run to a
full network download and turned proxy.golang.org stream errors into three
spurious red CIs - 0ed3a70: relay Dockerfile builder bumped to golang:1.26-alpine to
match go.mod - goroutine protection gate: trayhelper socket-death watcher allowlisted
with justification (separate-process helper, bounded read loop, respawn
handled by the main app)
Release Pipeline
- db5fc47: desktop release matrix builds green again (broken since the
tray series landed; v1.3.228 Release failed the same way)- tray action handlers (show / new-session / quit) were defined only in
tray_darwin.go while the socket dispatch in tray.go compiles on every
platform - Windows and Linux builds died on undefined methods. The
handlers are pure Wails runtime calls and now live in tray.go - trayhelper is now built with CGO_ENABLED=1 on darwin: energye/systray's
darwin backend is Objective-C CGO (Cocoa), so CGO_ENABLED=0 dropped
every platform symbol and the build failed
- tray action handlers (show / new-session / quit) were defined only in
- every fix in this release ships with a regression test pinning the
contract