Releases: Ark0N/Codeman
[email protected]
Patch Changes
- Terminal renderer hardening, SSE bandwidth cut, image paste, and a security tightening on the new live filter:
- Multi-primitive yield for write pacing (#85): replaces six raw
requestAnimationFramecallsites in the xterm.js write pipeline with a yielding helper that racesrequestAnimationFrame,setTimeout(50), and a tick Worker. Keeps the terminal responsive when the tab is backgrounded or occluded — Chrome's intensive-throttling no longer stalls long writes. - WebGL longtask auto-fallback (#83): a
PerformanceObserverwatches for ≥200ms WebGL frames; three within a 30s window disposes the WebGL addon and falls back to the canvas renderer. Decision is persisted in localStorage for 7 days, and?webgl=forceclears it. - Per-client live SSE subscription filter (#86): each connected client gets a stable UUID and can narrow its terminal stream to one session via
POST /api/events/subscribe— no EventSource reconnect on tab switches. Cuts SSE bandwidth roughly N× when N sessions are open. Lifecycle/metadata events (session:*,case:*,ralph:*,hook:*) now broadcast to every client so sidebars stay in sync. - Image paste and drag-and-drop into the terminal (#84):
Ctrl+Vand dropped images upload toPOST /api/sessions/:id/paste-image, save under${workingDir}/.claude-images/paste-${ts}.${ext}and type the path into the terminal. Hard 10MB cap, server-generated filename (no traversal),.svgdeliberately excluded from the allowlist to avoid a same-origin XSS path throughfile-raw. - SSE clientId validation: the per-client identifier introduced in #86 is now constrained to
[A-Za-z0-9_-]{8,64}at both ingress points. Without this, an authenticated attacker could send another tab's clientId to silently evict it from broadcasts, mutate any clientId's session filter to blackhole the victim's terminal stream, or growsseClientsByIdunboundedly via long IDs. The subscribe payload is also capped at 64 session entries of ≤128 chars each.
- Multi-primitive yield for write pacing (#85): replaces six raw
[email protected]
Patch Changes
- Finish the hostname-aware notification plumbing started in 0.6.7 and lock down the recent UI/runtime fixes with regression tests.
- Browser Notification API (OS-level desktop pop-ups, layer 3 of the 5-layer notification system) now uses
${originalTitle}: ${title}instead of the hardcodedCodeman:literal — so multi-host users running Codeman on laptop / dev box / NAS seecodeman:<host>: <event>consistently across tab title, tab-flash, Web Push, and OS notifications. - Inline session rename hardened against three corner cases: IME composition commits (Chinese pinyin Enter no longer ships half-composed text as the session name), mid-rename SSE deletion (orphaned
<input>no longer 404s on blur), and double-fire on stuck settle-once flag (closure-localsettledboolean replaces the boolean instance flag). - Test coverage backfilled for two prior shipped fixes:
<title>codeman:<host></title>server-side templating (#82): 8 tests covering defaultos.hostname(),--title-hostnameoverride, HTML-escape against<script>-style breakout, ampersand non-double-encoding, and template-tail byte-identical invariance.- tmux size-query helper (#80): 15 tests covering the browser-resize-between-attaches happy path, the query-then-die race, zero/negative/empty/non-numeric output fallbacks, and argv-form/timeout assertions that lock down the no-shell-interpolation guarantee. Inline 14-line query block extracted into a named
queryTmuxWindowSize()export insession.tsso the test surface is a pure function.
- Regression coverage added for
stripInkRedrawBloatroute helper. - CLAUDE.md and README.md updated to document dual-CLI env-prefix discipline (
CLAUDE_CODE_*vsOPENCODE_*), thexterm-zerolag-inputpublished-package side-effect of overlay edits, and the unified hostname prefix across tab title / tab-flash / OS notifications.
- Browser Notification API (OS-level desktop pop-ups, layer 3 of the 5-layer notification system) now uses
[email protected]
Patch Changes
-
- fix(client): preserve inline rename input across tab re-renders (#81) — Right-click → rename on a session tab no longer loses keystrokes when SSE traffic from sibling sessions triggers a tab re-render. Adds an
_inlineRenameActiveguard at the top ofrenderSessionTabs()and_fullRenameSessionTabs()so the in-progress input isn't destroyed mid-typing. Also fixes a latent double-fire offinishRename(blur + Enter could both invoke it). Drive-by: safer DOM child clearing in place ofinnerHTML = ''. - feat: hostname-aware window title (#82) — The browser tab title is now
codeman:<hostname>instead of the bareCodemanliteral, so users running Codeman on multiple hosts (laptop, dev box, NAS) can tell at a glance which tab points at which backend. New--title-hostname <name>CLI flag overrides the detectedos.hostname()when it's noisy or you want a cosmetic name. The title is templated into the served HTML on first byte (with narrow HTML escaping), so it's correct from the first paint and works without JavaScript. Title-flash logic now respects the per-host title. - perf: larger terminal tail on tab switch —
TERMINAL_TAIL_SIZEraised from 128KB to 1MB. When switching back to a busy session tab you now get ~8× more scrollback restored immediately. - fix: preserve response text in Ink redraw stripping —
stripInkRedrawBloat()rewritten from a first-VPA approach to cluster-based detection. The previous algorithm assumed all VPA escapes after the first one belonged to a single redraw region and discarded everything in between, which silently lost 100KB+ of legitimate Claude response text once a render had occurred. The new approach groups VPAs into clusters separated by ≥8KB gaps and only collapses clusters spanning ≥32KB, so streamed response content between redraw bursts is preserved. - docs:
CLAUDE.mdAdditional Commands gains the--title-hostnamerow;README.mdgets a "Hostname-Aware Window Title" subsection under Multi-Session Dashboard.
- fix(client): preserve inline rename input across tab re-renders (#81) — Right-click → rename on a session tab no longer loses keystrokes when SSE traffic from sibling sessions triggers a tab re-render. Adds an
[email protected]
Patch Changes
-
Terminal scrollback significantly increased — both the xterm.js viewport and the tmux backing buffer were bottlenecking how far back you could scroll. Three changes:
DEFAULT_SCROLLBACKraised from 20000 → 50000 lines (xterm.js, main terminal). The previous bump from 5000 only helped users with empty localStorage; existing users were stuck on whatever value they first picked up. The loader now treatsDEFAULT_SCROLLBACKas a floor — if your stored value is below the new minimum, you're raised to it automatically.- Subagent / teammate terminals (
panels-ui.js) were stuck at 5000; now use the sameDEFAULT_SCROLLBACKconstant (50000). - New tmux sessions now run with
history-limit 50000(tmux defaults to 2000). This matters for hard-reload / re-attach — without it, only the last ~2000 lines survive the round-trip back into a fresh xterm.
Tmux flicker on session re-attach fixed (PR #80 by @aakhter): the PTY now queries the existing tmux window size via
tmux display -pbefore spawning, instead of hardcoding 120x40. Previously, every re-attach forced tmux to resize down to 120x40, causing a visible flicker and one frame of scrollback loss. The-x 120 -y 40flag was also dropped fromtmux new-sessionso the initial size matches the first attaching client. UsesexecFileSync(not shell) for safety and falls back to 120x40 on any error.Docs: CLAUDE.md now documents two recurring foot-guns — the
xterm-zerolag-inputoverlay code is duplicated betweenpackages/xterm-zerolag-input/src/and inline insidesrc/web/public/app.js, so any overlay change must touch both; and the COM workflow explicitly includes a post-pushgh run watchstep to confirm CI before considering the release done.
[email protected]
Patch Changes
-
Mobile fix
- Android virtual keyboard: space character was silently dropped on touch devices using GBoard / SwiftKey / similar IMEs. Root cause: the input-event handler in
terminal-ui.jstreated any whitespace-only textarea value as proof that xterm had already processed the input. A lone space (' '.trim() === '') tripped this guard, so the space was consumed but never forwarded. Now skips only when the textarea is truly empty (or whitespace from a non-space key). Reported and diagnosed by @coolk8 in #79.
Docs
CLAUDE.md: added Zod.optional()-vs-nullgotcha (recurring trap from 0.6.3 / 0.6.4 incidents) and a more visible warning against running barenpm test(kills the host tmux session).docs/local-echo-overlay-plan.md: marked SHIPPED, corrected xterm version reference (v5.3.0 →@xterm/xterm^6.0.0).
- Android virtual keyboard: space character was silently dropped on touch devices using GBoard / SwiftKey / similar IMEs. Root cause: the input-event handler in
[email protected]
Patch Changes
- Fix "Failed to enable respawn: Invalid request body" error when selecting infinity duration (∞) in the respawn modal. Frontend was sending
durationMinutes: null, which Zod's.optional()schema rejected (it acceptsundefinedonly). The body now omits the field when no duration is selected.
[email protected]
Patch Changes
- Fix
- Allowlist
opusContext1mEnabledinSettingsUpdateSchema. Without this entry, the strict schema rejectedPUT /api/settings {"opusContext1mEnabled":...}withINVALID_INPUT, so the toggle's value never persisted across reloads. The frontend was already reading and writing this key (settings-ui.js:336/1137,session-ui.js:340), so saves were silently failing — users never noticed because the load path falls back tofalseon missing keys, hiding the bug. (#78)
- Allowlist
[email protected]
Patch Changes
-
Mobile UX
- Resume Conversation list (welcome page) reworked for narrow screens: 2-line title clamp so more of the first prompt is visible; case-aware subtitle that renders
#caseName(or#caseName/sub) whenworkingDirmatches a known case, otherwise falls back to the directory basename; inline⋯toggle that expands a detail panel with full prompt, full path, timestamp, size, and short session id;/Users/<user>/now collapses to~/alongside/home/<user>/. (#77) - Response viewer: ASCII diagram wrap toggle, dedicated mobile code-block layout, and chrome-stripping fallback when the model wraps its reply in extra markup. (#75)
- Mobile keyboard accessory bar no longer triggers vertical scroll. (#72)
Sessions & settings
- New
thinkingEffortsetting on session creation, withxhighoption and/effort maxmobile shortcut. (#73) thinkingEffortis now allowlisted inSettingsUpdateSchemaso it round-trips through PATCH /api/settings.envOverrides(CLAUDE_CODE_*/OPENCODE_*) are now passed to Claude via tmux env exports at spawn time instead of being written to<case>/.claude/settings.local.json. Eliminates UI/disk drift; the value lives onSession._envOverrides, is exported bytmux-manager.buildEnvExports(), and is persisted inSessionState.envOverrides. (#74)
Fixes
- Eye icon (active-session indicator) now follows
/clearto the new Claude conversation instead of getting stuck on the previous transcript. (#76) tmux-manager.reconcileSessionsnow uses|as the field separator, fixing parsing when session names contain other delimiters. (#71)
Docs
- CLAUDE.md: added
npm run knipto the dead-code sweep table and aCommon Gotchasentry documenting theenvOverrides→ tmux export flow.
- Resume Conversation list (welcome page) reworked for narrow screens: 2-line title clamp so more of the first prompt is visible; case-aware subtitle that renders
[email protected]
Patch Changes
- Internal cleanup and release hygiene:
- Dead-code sweep via knip: added
knip.jsonfor dead-code detection and ran a full sweep — removed unused test files, unused scripts, and narrowed internal module exports to the minimum surface area actually consumed. - Lockfile drift prevention:
version-packagesnow runsnpm install --package-lock-onlyand verifies the lockfile is in sync viascripts/check-lockfile-sync.mjs; CI runs the same check on every push/PR so version drift fails the build instead of reaching production. Resolves thepackage-lock.json/package.jsonversion mismatch that shipped in 0.6.0. - Docs tightening: archived 22 completed plan docs from
docs/, corrected file/handler counts inCLAUDE.md, documented the lockfile step in the COM workflow, and removed footer redundancy.
- Dead-code sweep via knip: added
[email protected]
Minor Changes
- Community contributions from @aakhter:
- feat (#66): Tab reorder shortcuts —
Ctrl+Shift+{andCtrl+Shift+}move the active session tab left/right, matching WezTerm convention. Order persists across reloads viasaveSessionOrder(). - feat (#67): Active tab visibility + Alt+N badges — active tab now has a bright green border with color-matched glow, and the first 9 tabs display number badges hinting at the
Alt+Nswitch shortcut. Badges update on reorder/rerender. - feat (#68): Clipboard API — new
POST /api/clipboardaccepting{text}broadcasts aclipboard:writeSSE event; connected browsers attemptnavigator.clipboard.writeText()with a manual-copy modal fallback when the page isn't focused. Auth-protected via the standard middleware. Useful for pushing snippets from remote sessions to the user's local clipboard. - fix (#65): Android Shift+key double character — pressing
Shift+Aon attached Android keyboards no longer produces "AA". Tracks xterm-handled keydown timestamps and skips the orphaned-input listener for 50ms after a real keydown, while still catching Gboard symbol-keyboard inputs (keyCode 229).
- feat (#66): Tab reorder shortcuts —