6f91b0c
fix(tools): switch bufio scanner for reader (#2884)
Click to expand commit body
* fix(tools): switch bufio scanner for reader
* chore(tests): update golden files
Kieran Klukas
created
65f30a1
perf(chat): skip re-parsing the rendered chat when nothing has changed
Click to expand commit body
Each frame the chat list is turned into a string with ANSI color codes
that we then have to parse back into cells before drawing. When the
chat list output is the same as the previous frame, we now reuse the
cells we already produced and skip the parsing step.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
0490a8a
fix(bedrock): honor reasoning_effort for Anthropic-on-Bedrock models (#2887)
Click to expand commit body
Bedrock routes through Fantasy's Anthropic implementation with a
different display name, so provider options must still be filed under
anthropic.Name for the language model to pick them up. Previously the
bedrock provider type was missing from getProviderOptions entirely, so
reasoning_effort and think were silently dropped.
Co-authored-by: JJ Bot <john.jansen+bot@me.com>
John Jansen
and
JJ Bot
created
1c7ccfd
perf(chat): reuse the rendered prefix of a streaming reply
Click to expand commit body
While a model is streaming a reply, we used to re-render the entire
message text every time a new chunk arrived. Now we keep the rendered
output of the parts that are clearly finished and only render the
trailing piece on each update. The check for what counts as a finished
part is conservative on purpose, so anything risky (open code blocks,
lists, tables, html blocks, link references) still falls back to a
full render. The visible output is the same.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
77b6c38
perf(chat): only render the chat lines that fit on screen
Click to expand commit body
Previously the chat list pulled the entire rendered output of every
on-screen item into a buffer and then trimmed it down to the viewport
height at the end. For very tall items, like a long reasoning block,
that meant building a buffer with thousands of lines just to throw
most of them away every frame. The list now stops collecting lines
as soon as the viewport is full, so per-frame work is bounded by the
visible window. Output is unchanged.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
6b101f3
perf(chat): skip re-rendering chat list items that have not changed
Click to expand commit body
The chat list now remembers what each item rendered last frame and
reuses it when nothing about that item has changed. Once a message
turn is fully done, its rendered output is reused verbatim on every
subsequent frame for as long as it stays unchanged. Resizing the
window, focusing or selecting an item, dragging a selection over it,
toggling a thinking block, and any other state change still triggers
a fresh render. The visible output is identical to before; the work
to produce it is much less.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
295a62d
fix(ui): calculation bug that would cause modified files to wrap
Christian Rocha
created
e0a8e39
chore(legal): @johnjansen has signed the CLA
There still seems to be a TUI-sync issue on upstream/main where
the assistant cuts off mid-sentence on screen even though the
DB has the full response. Two recent PRs probably get most of
the way to fixing it: #2840 reordered the agent's
TypeAgentFinished notification past the activeRequests cleanup,
and #2836 made channelBufferSize actually honored. In
power-user cases the default (64) is still too small, though.
A streaming turn calls messages.Update on every OnTextDelta /
OnReasoningDelta callback, and the TUI's glamour re-render
periodically stalls the Update loop for tens to hundreds of
milliseconds at a time. 64 slots fill before drain catches up
and the non-blocking publish in broker.go silently drops the
rest.
This diff adopts a pretty aggressive fix -- 64 -> 4096 covers a
long turn at typical SSE rates even under pathological View()
stalls. Cost is a few MB of ring-buffer allocation across all
brokers, comfortably inside any modern dev machine's budget;
users on tighter memory targets can still tune via
NewBrokerWithOptions.
Drive-by cleanup: maxEvents (struct field + NewBrokerWithOptions
param) is set to 1000 by default but never read anywhere in
tree -- it's bufferSize, not maxEvents, that actually bounds the
queue. Drop maxEvents on the theory that misleading dead code
is worse than no code.
💘 Generated with Crush
Assisted-by: Claude Opus 4.7 via Crush <crush@charm.land>
61ee2d2
fix(db): use connection pool to avoid corrupted writes
Kieran Klukas
created
02b783a
fix(permission): fix publish-before-lock race and use O(1) session permission lookups
Click to expand commit body
Move notification publish inside requestMu lock to prevent inconsistent
UI state, and replace the sessionPermissions slice with csync.Map
for constant-time persistent permission lookups.
💘 Generated with Crush
Assisted-by: DeepSeek V4 Pro via Crush <crush@charm.land>
Kieran Klukas
created
43b986c
perf(chat): show only the tail of long reasoning blocks when expanded
Click to expand commit body
When a reasoning block is expanded, show only the most recent few hundred
lines by default with a hint that more lines are hidden, instead of
rendering the entire thing. Clicking again shows the full block.
This keeps the UI responsive when models produce very long reasoning.
Co-Authored-By: Charm Crush <crush@charm.land>
9b8b888
fix(prompts): don't include ripgrep and gh prompts in testing
Kieran Klukas
created
0c1014e
feat(prompts): extend templating system to more prompts
Kieran Klukas
created
5ad8bee
feat(prompts): template prompts and add github and ripgrep info
Click to expand commit body
Co-authored-by: Tai Groot <tai@taigrr.com>
Kieran Klukas
and
Tai Groot
created
8370edb
perf(chat): cache the parts of an assistant message separately
Click to expand commit body
Each assistant message has up to three sections — thinking, response, and
errors — and previously a new streamed token re-rendered all of them. Now
each section is cached on its own, so streaming a response no longer
re-renders the (often long) thinking block above it.
Co-Authored-By: Charm Crush <crush@charm.land>
e112368
fix(config): scope crush.json discovery to the current repo
Click to expand commit body
The upward search for crush.json had no boundary and would walk
all the way to the filesystem root, which meant a stray crush.json
placed high in the tree could be picked up by every project beneath
it. This applies the same project boundary used for .crush discovery.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
e2e0bc0
fix(config): scope .crush discovery to the current repo
Click to expand commit body
When Crush starts up it looks for an existing .crush directory by
walking from the working directory toward the filesystem root. In
layouts with several worktrees of the same project under a common
parent, that walk could end up putting crush.db files in the project
root in worktrees.
This stops the walk at the git working tree root, when one can be
detected, and otherwise at the working directory itself. Each project
should now get its own .crush as expected.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
79b2d61
feat(fsext): stop upward lookup at a boundary directory
Click to expand commit body
Add variants of the upward filesystem search that stop at a
caller-supplied boundary directory instead of walking all the way up
to the filesystem root or to $HOME. Callers that want to avoid adopting
matches from outside their project can now express that boundary
explicitly. Existing callers and behavior are unchanged.
Co-Authored-By: Charm Crush <crush@charm.land>
Group rapid streaming updates into one save and one notification per short
window instead of one per token. Important updates like finishes, tool
calls, and errors still go through immediately. Cuts database writes and
UI redraws by orders of magnitude during long responses.
Co-Authored-By: Charm Crush <crush@charm.land>
c853a93
fix(config): always resolve the data directory to an absolute path (#2883)
Click to expand commit body
Co-authored-by: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
771117c
perf(chat): cache the prefixed render of chat messages
Click to expand commit body
Avoid rebuilding the focus and selection prefix for every line of every
message on every frame. Each item now keeps the prefixed output cached
and only rebuilds it when something actually changes.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
dd1be0e
refactor(server): derive per-host cache dir from parsed host URL
Click to expand commit body
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
2dba83a
test(server): regression for the client/server spawn race
Click to expand commit body
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
d41c118
fix(server): serialize concurrent server spawns with a per-host lock
Click to expand commit body
When two clients started up at the same time they would both try to
spawn a server and one would lose the bind race, leaving a confusing
log behind. Take an exclusive file lock around the spawn-and-wait
sequence, re-check health after acquiring the lock, and skip the spawn
entirely if a peer client has already brought the server up. The lock
is released as soon as the new server is ready.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
d17d61c
fix(server): spawn after stale shutdown + handle socket errors
Click to expand commit body
Two related gaps in the client startup path. After a version mismatch we
were shutting the old server down and then never starting a new one,
leaving the next caller to time out against a missing socket. And any
unexpected error from inspecting the socket path (something other than
"not found") was silently ignored, so we'd fall straight into the same
timeout. Both paths now converge on "needs (re)start" and we try to
clean up any stale file in the way before spawning.
Co-Authored-By: Charm Crush <crush@charm.land>
2235a49
fix: limit view size checks to returned content (#2785)
Greg Slepak
created
24da509
fix: properly follow the `Assisted-by` header spec (#2871)
Click to expand commit body
We were not using the correct format. According to the SPEC it should be:
Assisted-by: AGENT_NAME:MODEL_VERSION
So now it'll look like this:
Assisted-by: Crush:kimi-k2.6
See:
https://docs.kernel.org/process/coding-assistants.html#attribution
Andrey Nering
created
8021114
fix(server): keep the spawned server alive after the parent exits
Click to expand commit body
The parent process was creating the detached server via a context-bound
command, so when the parent exited or its context was cancelled the
runtime would also kill the brand new server we had just spawned. Drop
the context binding and rely on the existing platform-specific detach
to give the server a life of its own.
Co-Authored-By: Charm Crush <crush@charm.land>
Christian Rocha
and
Charm Crush
created
9b366c3
fix(server): probe readiness over HTTP instead of statting the socket
Click to expand commit body
Cold starts of CRUSH_CLIENT_SERVER=1 frequently failed with a stat error
because the spawned server creates the socket file as the last step of
initialization, well after the parent had given up. Replace the stat
polling with a real HTTP probe against /v1/health, treat any 2xx as
ready, and make the total budget overridable via CRUSH_SERVER_READY_TIMEOUT.
Drop the now-redundant CreateWorkspace retry loop.
Co-Authored-By: Charm Crush <crush@charm.land>