Commit graph

241 commits

Author SHA1 Message Date
patriceckhart
f9d14252dc Fix swarm inbox listener close race 2026-05-20 20:31:13 +02:00
patriceckhart
b13a9a6a4d Embed zot docs in binary 2026-05-20 20:25:29 +02:00
patriceckhart
d46f1d5824 feat(ext-panel): allow invisible selection marker via U+200B
ext_panel_dialog.Render sniffs the leading glyph of each panel line
to decide which row is selected and apply the theme's selection
band: today that's '> ' (U+25B8) or '* ' (U+25CF), both visible.
Extensions that want the highlight without a visible glyph had no
way to opt in - they had to ship the arrow.

Adds U+200B (zero-width space) as a third recognised prefix.
Extensions can now emit '\u200B' at the start of the selected row
to get the blue selection band without any visible marker; the
character renders as zero columns so other rows that omit it line
up perfectly. The visible arrow markers keep working unchanged.

Used by zot-workspaces to highlight the cursor row without
inserting a triangle into the otherwise clean list.
2026-05-19 19:48:17 +02:00
patriceckhart
e48f4dda76 feat: runtime cwd switching via hidden /cd and extension submit_slash
Adds the plumbing needed to let an extension jump the running zot
session into a different working directory without restarting the
process. Two pieces:

1) Hidden /cd <path> slash command

   * accepts ~/abs/relative paths, validates the target is a real
     directory
   * cancels the active turn, flushes + closes the current session
   * re-roots the shared sandbox (the /jail state is preserved
     verbatim - if jailed it stays jailed, just pointed at the new
     cwd)
   * rebuilds the agent via the existing buildAgent() so tools,
     AGENTS.md addendum, system prompt, and sessions dir all bind
     to the new cwd
   * opens a fresh session in the new cwd's bucket (matches the
     semantics of relaunching with zot --cwd <path>)
   * pushes the new state into the running Interactive via a new
     ApplyChangedCWD method and re-scopes the swarm dashboard

   /cd is not in slash_suggest's catalog, not in /help, not in the
   README. It's in a new hiddenSlashCommands list so the dispatcher
   accepts it without surfacing the verb to autocomplete. The
   slashCancelsTurn switch returns true for /cd so it never races
   with a streaming turn.

   InteractiveConfig.ChangeCWD is the optional host hook; embedders
   that don't wire it surface 'host did not wire ChangeCWD' instead
   of no-oping.

2) submit_slash extension protocol frame

   Extensions can now send a spontaneous {type:'submit_slash',
   text:'/...'} frame from any handler (notably panel_key) to run
   a slash command in the host TUI as if the user had typed it.
   The host refuses anything that doesn't start with '/' and logs
   the refusal to the extension's stderr log file, so a misbehaving
   extension can't sneak a plain-text model prompt through this
   path.

   HostHooks gains a SubmitSlash(text string) method; the three
   existing implementers (interactive, non-interactive, rpc) and
   the test stub now satisfy it. Only the interactive hook does
   anything; the rest no-op since slash commands aren't meaningful
   outside the TUI.

   Interactive.SubmitSlash routes the text through runSlash with
   the same cancel-active-turn-if-destructive treatment the editor
   uses for typed commands.

The workspaces extension drives this end-to-end: pressing Enter on
a row sends panel_close + submit_slash '/cd <abs>', which jumps
zot into that directory in place.
2026-05-19 19:38:47 +02:00
patriceckhart
ad93054ac4 feat(editor): extend path tab-completion to /btw and /swarm editors
The shell-style path tab-completion added in the previous commit only
ran against the main interactive editor; /btw and /swarm have their
own *tui.Editor instances inside their dialogs and routed Tab through
editor.HandleKey untouched, so '~/Dev'+Tab inserted nothing in those
modes.

Refactored the completion into a free helper:

  tryPathTabCompleteEditor(ed *tui.Editor, cwd string) bool

The Interactive method is now a thin wrapper that adds frame
invalidation. btwDialog gained a cwd field (set by Open) and calls
the helper before forwarding to editor.HandleKey. swarmDialog
already tracked d.cwd; both its prompt-editor and spawn-editor
paths now run the helper before HandleKey, gated to skip when the
@-picker popup is active so Tab there still selects the highlighted
chip.

Net effect: ~/Dev+Tab, ./int+Tab, cmd/+Tab, etc. now work the same
way in the main composer, in /btw side chats, and in /swarm spawn
and follow-up prompts.
2026-05-19 18:50:05 +02:00
patriceckhart
8096aebd0c feat(editor): shell-style tab-completion for path tokens
Typing a path-like token and pressing Tab in the editor now completes
it against the filesystem, the way bash / zsh do. No popup, no UI -
the token is rewritten in place.

Recognised shapes:
  ~ or ~/foo       - expanded via os.UserHomeDir(); the displayed
                     token keeps its ~ form after completion
  /abs/path        - absolute
  ./foo, ../foo    - relative to cwd
  foo/bar          - any token containing a slash, relative to cwd

Bare words ('hello', 'fix') without a slash or tilde are still no-ops
on Tab so plain text isn't disturbed.

Behaviour matches a typical shell:
  - one match: full replace, trailing / appended for directories so
    the next Tab can dive in
  - multiple matches: completes to the longest common prefix; if the
    prefix is already what was typed, Tab is a no-op (no second-tab
    'show options' list yet)
  - dotfiles hidden unless the user typed a leading dot

Tab inside the slash-command and @-file popups still does what it did
before; the new path completion only kicks in when neither popup is
active.
2026-05-19 18:44:01 +02:00
patriceckhart
4f008e8871 fix(@-picker): pick up files and folders created mid-session
fileSuggester.scan() cached the directory listing keyed only on the
absolute path, and the only invalidation paths (Reset / Invalidate /
SetCWD) never fired for in-place filesystem changes. Once the picker
had scanned the cwd, any later mkdir or touch was invisible until
zot restarted.

Key the cache on (path, mtime) instead. Stat the browse directory on
every scan and re-read when its ModTime has moved; OSes bump dir
mtime on every entry add / remove / rename, so the picker now reflects
the filesystem within a keystroke. Stat is one cheap syscall and only
runs while the popup is open, so the input loop stays responsive on
large repos.

Added TestFileSuggesterPicksUpNewEntries to pin the behaviour: scan,
sleep past the fs mtime tick, mkdir, scan again, expect the new dir.
2026-05-19 18:37:36 +02:00
patriceckhart
81c913aef9 feat(/study): accept an optional file or directory argument
/study previously hard-coded the prompt to 'the current directory'.
It now takes an optional path - typed, drag-dropped, or selected via
the @ file picker - and tailors the prompt to whatever was passed,
distinguishing files from directories via os.Stat and rendering paths
under cwd as relative for readability. With no argument, behaviour is
unchanged.

Examples:
  /study                          -> current directory (old behaviour)
  /study internal                 -> directory internal
  /study [dir:internal/]          -> directory internal (via @-picker)
  /study cmd/zot/main.go          -> file cmd/zot/main.go
  /study [file:cmd/zot/main.go]   -> file cmd/zot/main.go (via @-picker)
2026-05-19 18:37:27 +02:00
patriceckhart
e0c933ad7e Allow styled extension panel lines 2026-05-19 17:47:27 +02:00
patriceckhart
25e7da2c01 tui: highlight selected rows and accent frame in extension panel
Style ext panel rows that start with the selection markers (▸ / ●) using
the theme's selection colors, pad them to full width, and keep ✓ glyphs
in the tool color. Render the panel header and bottom rule in the accent
color so panels stand out from regular dialogs.
2026-05-17 13:48:45 +02:00
patriceckhart
1aea23e419 swarm: drop git-worktree / isolation; agents share the host cwd
Each swarm subagent now runs with cwd == the parent zot's RepoRoot, just
like the main agent. No per-agent git worktree, no swarm/<id> branch, no
SetIsolation toggle, no '\''i'\'' dashboard shortcut, no --isolated flag. The
previous worktree flow was confusing (toggling '\''i'\'' on a running agent
couldn'\''t reseat its cwd, so edits kept landing in the host repo anyway)
and shipped without a real use case.

Concretely:

- delete internal/swarm/worktree.go and the WorktreeManager interface.
- Config loses Worktree; SpawnReq loses Isolated; Agent loses Branch and
  Isolated; AgentSnapshot loses Branch and Isolated; agentMeta loses
  branch and isolated (older meta.json files still decode \u2014 unknown JSON
  keys are ignored \u2014 and buildDetachedAgent coerces any stale per-
  worktree Dir back to the live RepoRoot so detached agents resume in
  the right place).
- Swarm.Remove no longer calls into any worktree manager, so it can'\''t
  accidentally git-worktree-remove the user'\''s actual source tree; it
  only clears <swarm-root>/agents/<id>/.
- runner.go drops the <Dir>/.zot/session.json fallback (every plausible
  Dir is now the user'\''s repo, where a stray .zot/ would litter the
  source tree); SessionPath is required and Spawn always populates it
  under <swarm-root>/agents/<id>/session.json.
- swarm dialog: remove isolate/SetIsolateFunc, the '\''i'\'' key handler, the
  MODE column, the mode/branch lines in the transcript header. Fix the
  transcript-view cursor row math (row += 4 was counting a now-removed
  branch row, leaving the caret one row above the editor accent bar).
- swarm slash command: drop /swarm isolate, /swarm unisolate, and the
  --isolated flag on /swarm new; trim the spawn-flag parser and tests.
- README and slash-suggest description updated; site copy updated in a
  separate commit.

Tests adjusted accordingly; full suite green.
2026-05-17 00:01:29 +02:00
patriceckhart
63e28ad156 Close swarm event log in follower test 2026-05-16 14:18:12 +02:00
patriceckhart
d7fe461910 Fix swarm tests on Windows CI 2026-05-16 14:12:03 +02:00
patriceckhart
37526a6286 Format swarm code 2026-05-16 14:01:23 +02:00
patriceckhart
36f190af31 Deliver sliding-in messages during agent loop 2026-05-16 12:47:38 +02:00
patriceckhart
467ad0a990 modes: adapt slide-back chord hint to terminal
The "Press Option+up to slide back into input" hint shown under the
sliding-in queue was correct on Ghostty, iTerm2 (Meta=Option),
Terminal.app (Use Option as Meta), Alacritty, and Kitty -- all of
which send CSI 1;3A for Option+Up, which the input parser reads as
KeyUp + Alt.

VS Code's integrated terminal (xterm.js on macOS) swallows plain
Option as a compose modifier by default, so Option+Up never reaches
zot as an Alt-modified arrow. Option+Shift+Up does work there:
xterm.js emits CSI 1;4A (Shift+Alt), which the parser already
accepts as alt=true. The binding has always worked in VS Code;
only the displayed hint was misleading.

Fix: a small slideBackChordHint() helper that returns
"Option+Shift+up" when TERM_PROGRAM=vscode and "Option+up"
otherwise. interactive.go's queue-hint row calls it instead of
hardcoding the chord. The binding itself is unchanged -- both
chords work on every terminal -- the hint just adapts to what the
host actually delivers.

README.md gains a one-sentence note under Queued messages
documenting both chords and that the hint adapts via
$TERM_PROGRAM.

Tests cover the VS Code branch, case-insensitive detection
(VSCode / VSCODE / VsCode), and the default for "", "ghostty",
"iTerm.app", "Apple_Terminal", "alacritty", "kitty".
2026-05-16 12:01:05 +02:00
patriceckhart
b11e6ed4e4 swarm: introduce /swarm dashboard, /btw-style transcript view, and per-session scope
A /swarm subsystem for long-running parallel subagents. Each agent runs
in its own subprocess against a fresh git worktree (branch swarm/<id>)
with its own persistent session file and unix-socket inbox; the parent
zot stays in the main session and pokes / observes them via the
dashboard.

Highlights:

- New internal/swarm package: Agent, Spawn/Resume/Kill/Remove, event log
  (events.jsonl), inbox protocol (listen/dial), worktree manager, exec
  runner that spawns "zot --swarm-agent ...".
- New internal/agent/swarm_agent.go: daemon-mode child entry point.
  Reuses the standard agent loop but persists turns to the supervisor-
  chosen session.json and streams events as JSONL on stdout. Mirror to
  events.jsonl is dormant while the supervisor's stdout pipe is alive so
  events do not get double-written.
- Resume reattaches in place: reuses the same worktree, session, branch
  and inbox path; carries forward the prior transcript replayed from
  events.jsonl. Resume no longer re-fires the original Task as a fresh
  user turn -- that was producing "agent busy; send cancel first" races.
- core.NewSessionAtPath plus an openOrCreateSession fallback so the
  child actually persists its session.json at the supervisor-chosen path
  on first spawn instead of running with sess==nil.
- Dashboard in internal/agent/modes/swarm_dialog.go + swarm_slash.go:
  list / new / kill / remove / resume / logs / send subcommands plus an
  interactive picker. Transcript view is /btw-style: an always-on
  inline editor at the bottom, streaming auto-follow, inline busy
  spinner with the agent's current activity such as "thinking" or
  "tool: edit". /model inside the spawn editor pops the global model
  picker.
- Per-session scope: each spawn is stamped with the host session's id
  and only shows in that session's /swarm dashboard. Pre-upgrade agents
  -- empty session_id -- remain visible everywhere as a safety net. The
  active scope is re-applied whenever loadSession swaps sessions.
- Resolve falls back to the provider's default model when the persisted
  cfg.Model is no longer in the catalogue, warns on stderr, and rewrites
  config.json so the next launch is silent.
- ReadEventLog folds back-to-back same-type identical-payload events
  within 250ms so events.jsonl files polluted by the old supervisor +
  mirror double-write read back cleanly.
- DrawLog gains an idle no-op fast path: identical buffer plus identical
  cursor = emit nothing, so the terminal's cursor blink keeps ticking in
  dialogs whose underlying agent is idle.

Slash UX:

- New /swarm command with subcommands; the suggester picks it up.
- README.md documents the full dashboard, CLI, and persistence story,
  and explicitly notes that /session export does NOT bundle subagents
  -- their worktree and unix-socket inbox cannot round-trip through a
  .zotsession.

Tests cover: SpawnReq + Resume lifecycle, session-id scoping + persistence,
default-child-args spawn vs resume contract, NewSessionAtPath at a fixed
path, model fallback when the configured model is gone, swarm dialog
behaviour -- auto-open editor, /model in spawn editor, transcript grows
without internal scroll, busy spinner, multi-message send -- event-log
dedup, swarm emitter dormant-until-orphan, and the DrawLog idle no-op +
change-breaks-fast-path invariants.
2026-05-16 11:53:20 +02:00
patriceckhart
797041288d tui: strip ANSI from prompt before wrapping so cursor lands at end
When the interactive editor's Prompt carried ANSI styling — the
themed "▌ " glyph that interactive mode builds via
cfg.Theme.AccentBar — the raw escape bytes leaked into wrapLine's
per-rune width counter. Each byte of the SGR sequence (ESC, '[',
digits, ';', 'm') reported runewidth 1, so an 11-byte color escape
inflated the perceived prompt width by ~10 cells. wrapLine then
made wrap decisions against that inflated width, locateCursor
walked the inflated bodies, and Render() returned a cursor column
that landed inside the wrapped row instead of at its visible end.

The bug was intermittent because depending on the typed buffer's
length the geometry sometimes aligned by accident. Drag-and-dropping
a long screencaptureui temp path into VS Code's terminal reliably
triggered it, since the path stays inline (the temp file is already
gone by paste time so collapseOrQuoteFilePaths -> pathExists
returns false -> falls through to verbatim insert).

Fix: in Editor.Render, do all wrap and cursor math against a
plain-text prompt (ANSI stripped via stripANSI), then re-attach
the styled original to the very first wrapped row's leading
substring before returning. Continuation rows already use an
indent of spaces only, so they need no styling fixup. wrapLine
itself stays ANSI-unaware on purpose: the rest of the codebase
relies on its simple rune-based behaviour for plain text and
making it ANSI-aware would be a much bigger change with regression
risk elsewhere.

Adds editor_ansi_prompt_test.go which reproduces the exact captured
live scenario (the ANSI-themed prompt + the verbatim screencaptureui
path + ' hello' typed afterwards) and asserts the cursor lands at
the visible end of the last wrapped row.
2026-05-13 11:13:20 +02:00
patriceckhart
8b4b62f240 tui: suppress \x1b[3J scrollback-clear on VS Code's terminal
VS Code's integrated terminal (xterm.js) interprets the
erase-in-display-3 escape (\x1b[3J) as "drop scrollback rows AND
snap the viewport to the top of the remaining buffer." Once the
user has reopened a terminal with VS Code's persistent-sessions
feature on, there is real replayed scrollback above the live
cursor, so the snap is visible: the host scrollbar yanks to the
top on every full repaint — first paint, Ctrl+L (Renderer.Clear),
and any writeFull(true) shrink.

Every other terminal we tested (iTerm, Ghostty, Kitty, Alacritty,
Apple Terminal) treats \x1b[3J as "drop scrollback rows without
moving the viewport," which is what we want.

Detect VS Code (and Cursor, which shares xterm.js) via
$TERM_PROGRAM == "vscode" in NewRenderer and stash the result on
the Renderer as keepScrollback. Gate all three emission sites
(resize handler, Clear(), writeFull(true)) through a single
helper clearScrollbackSeq() that returns "" when keepScrollback
is true and SeqClearScrollback otherwise.

Trade-off on VS Code: stale zot frames remain visible if you
scroll up in the terminal's scrollback. Strictly less disruptive
than the scrollbar yanking on every Ctrl+L, and limited to the
one terminal that actually has the bug.
2026-05-13 10:37:48 +02:00
patriceckhart
f47996bc82 agent: add 'zot update' subcommand for in-place self-update
Adds a CLI subcommand that downloads the latest GitHub release for
the current GOOS/GOARCH, verifies its sha256 against checksums.txt,
extracts the archive, and atomically replaces the running binary.

  zot update           install the latest release
  zot update --check   show whether one is available, install nothing
  zot update --help    usage

Dispatch follows the same router shape as runBotCommand /
runExtCommand in cli.go. Asset naming stays in sync with the
archives.name_template in .goreleaser.yaml (zot_<ver>_<os>_<arch>).
Reuses fetchLatestRelease + versionLess from update.go so the
"what's latest" answer is identical to the in-TUI banner.

Refuses to operate on dev builds (version 0.0.0) since the version
comparison is meaningless and we'd happily downgrade a freshly
compiled local build back to whatever ships on GitHub. $GITHUB_TOKEN
is honoured so private-repo releases work.

Unix: atomic os.Rename in place (the kernel keeps the running
binary's inode alive until exit). Windows: rename current aside
to .old, drop the new exe in, leave the .old for next-update
cleanup since the running process has it locked.
2026-05-12 21:27:11 +02:00
patriceckhart
43da5e5249 tui: reset auto-follow baseline on new turn to stop viewport jump
startTurnWithImages clears the previous turn's tool-call overlay and
pins scrollOffset to 0. Without also resetting prevChatLen/prevChatCols,
the auto-follow guard on the next render sees a synthetic negative
delta equal to the number of overlay rows that were cleared, and
nudges scrollOffset by that amount. On terminals that mirror zot's
chat-pane scroll into their native scrollbar this is visible as a
viewport jump the instant the user presses enter on a follow-up
prompt.

Zero them out in the same locked block so the guard short-circuits
on the very next render, the same way it already does on column
resize. The legitimate "user scrolled up while content streams in"
case is unaffected because prevChatLen is repopulated on that first
post-submit render.
2026-05-12 20:43:43 +02:00
patriceckhart
1030ae584d Hide /jail when sandbox is already jailed
/jail and /unjail are mutually exclusive actions, so only show the
one that actually applies in the current state.
2026-05-11 18:11:18 +02:00
patriceckhart
21b88f6a6b tui: drop cursor-home from forced-full-repaint clear too 2026-05-11 11:44:22 +02:00
patriceckhart
6dbe0b7b47 gofmt: realign const block in tui/terminal.go 2026-05-11 09:31:21 +02:00
patriceckhart
33a865b782 tui: drop cursor-home from clear-screen to stop vscode scrollbar jump 2026-05-11 09:27:08 +02:00
patriceckhart
ce78a49b87 add deepseek provider (api-key, openai-compatible v4 catalog) 2026-05-10 16:49:31 +02:00
patriceckhart
f4d678e61e Trigger full redraw on overlay close and new turn submit 2026-05-10 10:59:57 +02:00
patriceckhart
c01e026961 Stabilize chat rendering: remove forced full repaints, fix scroll/diff edge cases 2026-05-10 10:36:05 +02:00
patriceckhart
c98e701843 Persist compaction checkpoints in sessions 2026-05-09 23:02:54 +02:00
patriceckhart
facc709060 fix: session dialog highlight doubling, row overflow, and resize flicker
- DrawLog: invalidate cached bottom rows when selection-highlight
  escapes are present so VS Code's terminal doesn't leave stale
  background colors on the previous cursor row
- session dialog: hard-clamp row text to terminal width so long
  session summaries don't soft-wrap into adjacent rows
- Resize: clear scrollback alongside screen so stale wider content
  doesn't bleed through when the terminal is narrowed
2026-05-09 22:55:45 +02:00
patriceckhart
9f0629bcaf Support AGENTS.md context files 2026-05-09 18:37:27 +02:00
patriceckhart
25cb7d5003 remove /yolo slash command
The runtime escape hatch was redundant: --no-yolo's per-call dialog
already exposes 'yes-always-this-session' which flips ConfirmGate
into allow-all mode without a separate command. Once a session
starts with --no-yolo, the only way to disable confirmations is now
to either pick the always-this-session option in the dialog or exit
and relaunch.

- slash_suggest.go: drop the /yolo entry from the autocomplete list.
- interactive.go: remove the case "/yolo" dispatch (falls through
  to 'unknown command') and delete the orphaned runYoloOn method.
- README: drop the /yolo row from the slash-command table and the
  trailing reference in the --no-yolo flag description.
2026-05-08 08:18:16 +02:00
patriceckhart
09acdbd1d4 lowercase funny working lines 2026-05-08 08:13:30 +02:00
patriceckhart
9b4f4da559 spinner: capitalize working-line phrases
Sentence-case looks better in the TUI status area than all-lowercase.
2026-05-08 08:04:18 +02:00
patriceckhart
ef93175bf9 add Google Gemini provider
- internal/provider/gemini.go: REST client against
  generativelanguage.googleapis.com/v1beta/models/{id}:streamGenerateContent
  ?alt=sse, mapping our message/tool format to Gemini's Content/Part schema
  and translating SSE chunks into the existing assistant-message event
  stream. Handles text, tool calls, thought-summary parts, and per-model
  thinking config (thinkingBudget for 2.5, thinkingLevel for 3.x with
  Gemini-3-Pro pinned to LOW minimum).
- internal/provider/discover.go: DiscoverGoogle pages /v1beta/models and
  filters to chat-capable ids (skips embeddings, AQA).
- internal/provider/models.go: catalog entries for gemini-2.5-pro,
  2.5-flash, 2.5-flash-lite, 2.0-flash, 2.0-flash-lite.
- internal/auth: 'google' is a recognized provider; API-key probe hits
  /v1beta/models with x-goog-api-key. OAuth flows reject google with a
  clear 'API-key only' error since Gemini Advanced subscriptions don't
  issue API tokens.
- internal/agent: env lookup for GEMINI_API_KEY / GOOGLE_API_KEY,
  default model gemini-2.5-pro, NewClient wires provider.NewGemini,
  background model discovery, /login + /logout + rescue dialog all
  include google.
- README: new ### Google Gemini section with auth model, free-tier
  limits, and reasoning-config notes.
2026-05-07 21:15:34 +02:00
patriceckhart
90351066b1 Recover queued messages with Option+Up
Pressing Option+Up while the agent is busy now pops the most recently
queued ('sliding in') message back into the editor so the user can
edit and resend it. Repeated presses keep peeling messages off the
tail of the queue, newest first; each press replaces the editor
contents rather than appending. When the queue is empty the keypress
falls through to the existing scroll-up behavior.

A muted hint row underneath the chips advertises the shortcut, using
the same color as the model info on the status bar so it reads as
ambient metadata.
2026-05-07 19:41:27 +02:00
patriceckhart
63694afce8 Improve Telegram status and stop commands 2026-05-07 19:05:57 +02:00
patriceckhart
caac4915ed Fix PowerShell checksum parsing 2026-05-07 18:54:45 +02:00
patriceckhart
528ecf2db3 Hide unjail command unless jailed 2026-05-07 18:41:13 +02:00
patriceckhart
380eca9615 drop rescue status bar claim from readme 2026-05-06 20:46:29 +02:00
patriceckhart
0a85be3c33 add model rescue picker and silent transient retries 2026-05-06 20:40:31 +02:00
patriceckhart
0f332faf66 fix kimi empty assistant messages 2026-05-06 18:49:43 +02:00
patriceckhart
f37f42b189 fix windows installer checksum lookup 2026-05-06 18:26:11 +02:00
patriceckhart
25a4cafb4e fix kimi oauth token refresh 2026-05-06 18:19:42 +02:00
patriceckhart
168941f09e tui: separate live prose from tool boxes 2026-05-05 18:06:40 +02:00
patriceckhart
bfaaaa3dd9 provider: set explicit kimi pricing 2026-05-05 17:48:04 +02:00
patriceckhart
6c5c4f213a tui: make main-screen renderer viewport-safe 2026-05-05 17:33:34 +02:00
patriceckhart
ea10cbad79 openai: replay reasoning_content for chat completions 2026-05-05 15:15:07 +02:00
patriceckhart
7134fb7c2a provider: replay reasoning items and repair orphan tool results 2026-05-05 15:00:41 +02:00
patriceckhart
ae4e019ee4 tui: use DECSC/DECRC for bottom-band anchor; normalize \r in editor input
DrawLog now saves/restores the cursor at the top of the bottom band
instead of relying on relative up-N math that drifted when the
terminal naturally scrolled between frames. This fixes duplicated
transcript blocks with empty gaps (previously only ctrl+l recovered).

Also strip literal carriage returns from pasted/typed editor text
before rendering. A bare \r moves the terminal cursor to column 0
and overwrites the left side of the input row, which looked like
missing highlight segments on continuation lines.
2026-05-05 14:35:40 +02:00