Release Notes
Added
- Single-file multi-op file tools (
read_file / edit_file), one file per call — the path is named once for any number of operations. The E5 convergence replaces the four-tool read/edit surface (read_file, read_files, edit_file, edit_files — fs tools 7 → 5) with two tools that take one file and an operation list: read_file gains optional ranges: [{offset?, limit?}] (omitted/empty = whole file, unchanged bare output; a single window keeps the bare output too; 2+ windows render one === path === section per window, each with read_file's continuation footer, ≤ 16 windows), and edit_file takes edits: [{old_string, new_string, replace_all?}] (1..=16), applied in listed order with each edit matching the content the previous edit left — the same-file multi-edit workflow that previously required repeating file_path per item in edit_files. Atomicity strengthens: the edits all apply to an in-memory string and the file is written once at the end, so one failed edit rolls the whole call back (edit N: <reason>. File untouched., with the nearest-line hint and the edit's 1-based index in the call's own list); upfront validation rejects empty/identical/exactly-duplicated edits and the cap before any I/O. The old edit_files HashMap file-grouping layer is deleted outright; read_file_segment / apply_edit_ops / the CRLF gate / the nearest-line hint carry over unchanged, EditOp is now the #[derive(ToolItem)] wire item, and the pinned schema contract test tracks the new shapes.
- Batched search tools on ripgrep's library split (
grep / glob). grep moves from the hand-rolled single-threaded line scanner to grep-regex + grep-searcher + the ignore parallel walker: multi-threaded walking, .gitignore/.ignore semantics (target/, node_modules/ no longer scanned — rg rules: an explicitly given FILE is still searched, a DIRECTORY arg respects the ignore rules, ignored trees go through bash), binary NUL-quit detection, and dotfiles stay searchable (hidden(false)). Both tools accept 1..=8 patterns per call: grep's single-pattern output stays the flat path:line: text (legacy format, 500-row cap); multi-pattern output groups per pattern with a 200-row soft cap per pattern (a hot pattern cannot starve its siblings) under the 500-row global cap, an optional include glob filter, and optional context lines (0-5, rendered rg-style path-line- text, counted toward the caps); an invalid pattern renders as its group's error section while the rest still search (all-invalid fails the call). Results sort by (path, line, document order) so the parallel walk's nondeterministic order never leaks. glob's batched patterns compile up front — any invalid one fails the call (a flat list has no per-pattern error slot: deliberate asymmetry) — and first-match-claims dedup across overlapping patterns. All existing guards survive the rewrite: the 16MB file skip, the 500-char match-centered line window (truncate_around_match unchanged, now called inside the Sink), the boundary ctx.resolve, and the pinned schema contract test updated to the new patterns/include/context shape.
Fixed
- "Load earlier messages" no longer splits tool calls from their results. The earlier-page path builds the whole page into an unmounted
DocumentFragment before a single insert into the pane, but the result-merge step queried the PANE for the call card ([data-tool-call-id]) — at that moment the card built earlier in the SAME page was still inside the fragment, the query always missed, and every same-page pair degraded into a call card plus an anonymous orphan "result" card (the initial tail appends directly into the pane, so only the click-loaded path broke; page-boundary alignment to user messages only protects ACROSS pages). appendHistoryMessage now carries a per-page tool_call_id → card registry that the earlier-page loop maintains and the tool branch consults before the pane fallback. Pinned by a pagination test that click-loads a page containing a tool round.
- Streaming follow no longer dies when an expanded reasoning block shrinks mid-stream. The stick machine's only detach signal was "the scroll event reads as an up-scroll" — but while pinned at the bottom, an incremental streaming render whose boundary frame nets NEGATIVE height (paragraph-commit reflow, code-fence fold-back removing committed nodes) makes the browser clamp
scrollTop down to the new bottom and dispatch a scroll event that reads exactly like the user leaving. One such clamp detached the stick state and silently no-op'd every later delta's scheduleFollow until the user scrolled back into the 96px re-attach window — visible when streaming an expanded reasoning block (collapsed blocks never occupied scroll height, hence "probabilistic"). Detach now requires scrolling up AND off the bottom (scrollTop + clientHeight < scrollHeight - 2px): a clamp lands exactly on the bottom and is no longer mistaken for intent. Accepted cost: the first ≤2px of a real scroll-up from the bottom may detach one event late — the next tick always leaves the tolerance. Pinned by a new stick-machine test suite driving mocked scroll metrics.
Install flux-server 0.2.2
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/km0e/flux/releases/download/v0.2.2/flux-server-installer.sh | sh
Install prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/km0e/flux/releases/download/v0.2.2/flux-server-installer.ps1 | iex"
Download flux-server 0.2.2