Skip to content

1.7.1#77

Merged
liftaris merged 16 commits into
mainfrom
dev
May 22, 2026
Merged

1.7.1#77
liftaris merged 16 commits into
mainfrom
dev

Conversation

@liftaris
Copy link
Copy Markdown
Owner

@liftaris liftaris commented May 22, 2026

Patch release: fixes from the wiki-driven audit batch (#76).

  • fix(ui): theme picker crash — command registry pure-ref, DialogHost ErrorBoundary, DialogSelect onMove gated to user moves, prefs.set no-op on unchanged value
  • fix(session): stale-sid race on /new — reset gateway sid before session.create
  • fix(events): gateway stderr renders as styled error, untruncated
  • control: bind 127.0.0.1 by default, warn on exposed bind, docs/control.md
  • perf(theme): lazy-load theme JSONs (manifest-backed picker, active theme primed at boot)
  • docs: terminal.resize intentional-omission note; AGENTS.md default branch corrected to dev

github-actions Bot and others added 16 commits May 21, 2026 07:17
Error-ish gateway.stderr lines now render as styled error rows instead of
plain system lines, and the 200-char truncation on the transcript row is
gone — full line passes through. The gw.logs ring buffer already captures
every stderr line untruncated via GatewayClient.log(), so /logs (gw.tail)
still offers the complete traceback regardless of what the transcript
surfaces.
newSession mirrored switchProfile's cleanup except for the gateway sid
clear. Without gw.setSession("") up front, any RPC or event emitted in
the window between reset() and setSession(new) carried the outgoing
session_id via gateway-client's auto-injection — a narrow race where
stale-sid events can be misattributed to the new session.

Adds a MockGateway-backed regression test: asserts the second
session.create (from /new) has no auto-injected session_id, and that
session.close still receives prev explicitly.
…l.md

Bun.serve without hostname binds 0.0.0.0 — CONTROL=1 was silently
network-reachable. Default CONTROL_BIND=127.0.0.1. If the user overrides
to a non-loopback host, start() writes a yellow stderr banner and
AppInner raises a 15s warning toast so the exposure is never silent.

warningFor(on, bind, port) factored out so tests exercise the decision
without re-importing the module under different env (BIND is captured at
module load, mirroring the existing `enabled` pattern).

docs/control.md covers what it is, env vars, endpoints, security
posture, and the ptyrun/e2e use case.
…Boundary

CommandProvider.register used to bump a state counter on add and on
cleanup. Nothing downstream actually read the counter — open() and
the palette's useKeyboard read the registry lazily at press time, so
the re-render did no work. But when a caller's register effect had a
dep that flipped mid-commit (slash.tsx lists themeCtx; the theme
picker fires ctx.set on every arrow via onMove), the cleanup's
setState rescheduled CommandProvider during its own passive-unmount
phase and the nested-update limit tripped. Switch the registry to a
pure ref; (un)register is now a plain Map write.

Wrap the dialog overlay in a class Boundary so the next latent dialog
loop (Rollback, Branch, Eikon Generate and the theme picker's own
DialogSelect current/onMove interplay) degrades to a dismissed dialog
+ toast instead of killing the TUI. Boundary sits inside
DialogProvider so it can call clear() + toast.error() directly.

Tests: test/command-registry.test.tsx covers the register contract
under rapid mount/unmount bursts; test/dialog-boundary.test.tsx
mounts a dialog whose body throws and asserts the Boundary catches,
dismisses, and the error surfaces via toast.
Drop the static import of every theme body from src/theme/builtin.ts.
Names + a few preview colors live in a generated manifest; theme
bodies load on first set() via dynamic import(`./themes/${name}.json`)
and are memoized in src/theme/load.ts.

src/index.tsx primes the active theme before render() so the first
frame paints without a fallback flicker. test/preload.ts does the
same for every bun test mount.

New: scripts/gen-theme-manifest.ts regenerates src/theme/manifest.ts
from the JSONs on disk — run when a theme is added, removed, or its
primary/accent/background changes.
…et no-ops on unchanged value

The registry setRevision removal was necessary but not sufficient: the
remaining loop was DialogSelect's cursor-sync effect (cursor <- index of
props.current) ping-ponging with the move-notify effect (onMove ->
ctx.set -> props.current). Gate onMove behind a moved ref that only
keyboard nav and mouse hover set. prefs.set also returns early when the
value is unchanged so redundant preview writes don't notify subscribers.
Fixes: theme picker crash, dialog ErrorBoundary, control-server hardening, lazy themes, stderr styling, /new race
@liftaris liftaris merged commit 1cf9e38 into main May 22, 2026
3 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.7.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant