Commit graph

23 commits

Author SHA1 Message Date
patriceckhart
d653cc179d tui: slash commands work while a turn is in flight
previously typing any slash command during a turn was rejected with
"cancel the current turn (esc) before running a slash command".
annoying and unnecessary for read-only commands, and the
destructive ones can cancel the turn for you.

read-only commands run immediately, parallel to the streaming
turn: /help, /jump, /sessions, /lock, /unlock, /exit.

destructive commands trigger cancelAndWaitForIdle first (cancels
the turn ctx, polls i.busy at 10ms intervals, gives up after 2s
as a safety cap so a wedged http stream cannot freeze the ui
forever): /clear, /compact, /login, /logout, /model. once the
turn goroutine has wound down they run on the now-quiet agent.

slashCancelsTurn(head) in slash_suggest.go is the single source
of truth for which commands need the wait. readme updated to
match the new behaviour.
2026-04-19 11:21:37 +02:00
patriceckhart
64704875d2 tui: /jump to scroll to past turns, render cache for long transcripts
/jump:
- new slash command; opens a picker listing every user turn in
  the current session (timestamp relative, tool count badge, first
  line of the prompt). \u2191/\u2193 + enter scrolls the viewport to put
  that turn's user-message header at the top row. non-destructive,
  transcript untouched
- runes extend a live filter; backspace shortens. '/jump <text>'
  pre-applies the filter; exactly-one-match auto-jumps without
  showing the picker
- while parked on a past turn the scroll-up note reads 'viewing
  turn N of M \u00b7 pgdn to catch up' instead of the generic row
  count. scrolling back to the tail (or starting a new turn, or
  /clear) resets the parked state automatically
- view.go: new MessageAnchor type + BuildWithAnchors so the dialog
  can resolve msgIdx -> first rendered row

perf for long transcripts (the whole ui stutters on ~50 messages):
- view.renderCache: per-message memoisation keyed by (fnv1a of
  role+content, width, expandAll). finalised messages never change
  so the cache hit rate is ~100% after the first render. streaming
  partials and in-flight tool-call views stay uncached by design
- BuildWithAnchors now pre-sums line counts and allocates
  in a single make() instead of 50 appends with log2(N) backing-
  array memcpys
- truncateToWidth fast path: byte-length <= cols implies cell-width
  <= cols, so we skip the rune-width loop entirely. covers the huge
  majority of lines in a session
- cache purged on /clear, /compact completion, and session swap
  (applySessionSelection); resize invalidates implicitly via the
  width key. LRU eviction at 4x message count caps memory

impact: a 50-msg / 2000-line transcript went from unresponsive-
while-typing to drawing in well under a frame. measured locally
with go-perf traces; no change to correctness.
2026-04-18 12:22:16 +02:00
patriceckhart
7141ebd45f readme: drop private-repo install caveats
the repo will be public by the time anyone reads this, so the
GITHUB_TOKEN / GOPRIVATE scaffolding just adds noise. installers
and 'go install' were already coded to work unauthenticated on
public repos; no code changes needed.
2026-04-18 11:51:09 +02:00
patriceckhart
8e546bde70 tui: show 'update available' banner at top of chat
- internal/agent/update.go: check github releases api for a newer
  tag than the compiled-in version, cached in $ZOT_HOME/update-check.json
  with a 12h ttl so startup never hits the network twice. honours
  $GITHUB_TOKEN for the window while the repo is private; falls back
  to silent no-op on any failure. skipped entirely on dev builds
  (version = 0.0.0 or dev)
- internal/agent/modes/update_banner.go: yellow-framed block with
  the new version, the current version, the one-liner install
  command appropriate for the platform, and a link to the release
  page. rendered above the welcome / transcript so it's the first
  thing the user sees
- wired through via InteractiveConfig.UpdateInfoChan to avoid an
  import cycle (modes -> agent). cli.go kicks off the check async
  and feeds the result in

note: no 'dismiss' key yet \u2014 the banner stays until you update to
the shown version. if the nagging gets annoying we can add a
per-version dismiss cache later.
2026-04-18 11:49:22 +02:00
patriceckhart
728cf4e2b1 tui: allow chat scroll (up/down/pgup/pgdn) while the agent is busy
the up/down handlers required !i.busy before routing to scrollBy,
which meant you couldn't scroll back through a long streaming reply
while it was still arriving. dropped the busy check \u2014 chat scroll
now works in both states, consistent with pgup/pgdn which never
had the restriction.
2026-04-18 11:33:05 +02:00
patriceckhart
c0f685f498 tui: show /help at the bottom of the transcript instead of the top
the help block was prepended to the chat, which pushed any existing
conversation off the top of the viewport on anything but the
shortest sessions. appending it (with scrollOffset=0 so the viewport
sticks to the bottom) means /help is always visible right above the
editor, exactly where the user's eye is already looking.

login / model / sessions dialogs already render in the bottom-sticky
band between chat and editor, so they weren't affected.
2026-04-18 11:31:06 +02:00
patriceckhart
8a13141ace release: use rare opt-out token that prose won't match
the previous guard string kept matching because i literally mentioned
it in my own commit messages when documenting the feature. switched
to a form with an equals sign that will never appear in ordinary
english.
2026-04-18 11:23:02 +02:00
patriceckhart
4d847ec633 release: remove debug job, gate brew upload on HOMEBREW_TAP_TOKEN
- debug job served its purpose (proved workflow_run fires correctly)
  and is gone
- restore the [skip-release] guard
- brews.skip_upload is now a go-template that evaluates to true when
  HOMEBREW_TAP_TOKEN is empty, so tag pushes before the tap is
  created don't fail the whole release (v0.0.1 cut fine but the
  goreleaser exit code was 1 because the brew step 401'd)
2026-04-18 11:21:32 +02:00
patriceckhart
75aa6d4771 ci: add debug step to dump workflow_run payload
the release job kept getting skipped even though the if-expression
should have evaluated true. adding a diagnostic job (no if-filter)
that prints github.event.workflow_run so we can see what fields
are actually populated on the webhook payload at eval time.
removing the [skip-release] guard temporarily to reduce variables.
2026-04-18 11:17:10 +02:00
patriceckhart
f0014f10fa release: rename skip directive to [skip-release] (hyphen)
the previous [skip release] (space) matched my own commit message
that literally described the feature, which caused the first green
ci run to skip the release instead of cutting v0.0.1. hyphenated
form is much less likely to show up in ordinary prose.

also switch the job-level if from folded-scalar yaml to an inline
${{ }} expression for robustness.
2026-04-18 11:15:28 +02:00
patriceckhart
63547d43ba release: auto-tag and publish on every green ci run
- release.yml now triggers on workflow_run of ci (completed+success),
  not on bare push, so we never publish binaries of broken code
- checks out github.event.workflow_run.head_sha, computes the next
  vX.Y.Z by bumping the patch of the newest existing tag (starts at
  v0.0.1), pushes the tag, runs goreleaser
- supports [skip release] in the commit message for docs/ci-only
  commits that shouldn't cut a version
2026-04-18 11:13:39 +02:00
patriceckhart
c0adbc4315 fix ci on windows: close reopened session in TestSessionRoundTrip
OpenSession returns a Session whose writer holds an append handle to
the jsonl file. The test never closed it, so t.TempDir's cleanup hit
'The process cannot access the file because it is being used by
another process' on windows (posix happily deletes open files).
Register a t.Cleanup that closes the reopened session.
2026-04-18 11:01:42 +02:00
patriceckhart
682c64f494 fix ci on windows: split detach helper into posix/windows variants
syscall.SysProcAttr.Setsid is posix-only — unknown field on windows.
Extracted the detach-on-start logic into a detachChild function
variable, implemented in botcmd_unix.go (Setsid) and botcmd_windows.go
(DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP creation flags).
2026-04-18 10:58:10 +02:00
patriceckhart
2158c272af fix ci: portable syscall.Select via x/sys/unix; gofmt pass
- rewrite resize_unix.go on top of golang.org/x/sys/unix so the
  peek-stdin helper compiles on linux (Select returns (int, error),
  Timeval.Usec is int64) as well as darwin (int32, error-only)
- promote golang.org/x/sys to a direct dep
- gofmt -w . (11 files of alignment drift from recent edits)
- install.sh / install.ps1: accept $GITHUB_TOKEN so the installers
  work against the repo while it's private; no-op on public repos
- README: document the private-repo install paths (PAT for curl|bash
  and powershell, GOPRIVATE for go install)
2026-04-18 10:55:42 +02:00
patriceckhart
4712f5e0e3 add installation process and github workflow 2026-04-18 10:50:02 +02:00
patriceckhart
6aea65ea02 change readme 2026-04-18 10:35:54 +02:00
patriceckhart
6324668df8 add auto compaction 2026-04-18 10:34:08 +02:00
patriceckhart
dbe6763736 add collapsible code blocks 2026-04-18 10:30:29 +02:00
patriceckhart
6bb3e9e23f fix code formatting 2026-04-18 10:23:02 +02:00
patriceckhart
a4e6cde56f fix code highlighting 2026-04-18 10:16:06 +02:00
patriceckhart
091d5df5ef add logo to callback page 2026-04-18 10:15:53 +02:00
patriceckhart
d8a0cba4fc add telegram bot bridge 2026-04-18 09:15:46 +02:00
patriceckhart
6cced27476 initial commit 2026-04-17 20:36:38 +02:00