From 23b4dfcd82c4e7aee7d051860232b8ca3a958068 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 9 May 2026 03:23:34 +0200 Subject: [PATCH] chore: version packages Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 11 +++++++++++ CLAUDE.md | 5 +++-- docs/local-echo-overlay-plan.md | 10 ++++++---- package-lock.json | 4 ++-- package.json | 2 +- src/web/public/terminal-ui.js | 2 +- 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ced0950..57070eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # aicodeman +## 0.6.5 + +### 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.js` treated 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-`null` gotcha (recurring trap from 0.6.3 / 0.6.4 incidents) and a more visible warning against running bare `npm 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). + ## 0.6.4 ### Patch Changes diff --git a/CLAUDE.md b/CLAUDE.md index 3d175394..1a876bad 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co | Type check | `tsc --noEmit` | | Lint | `npm run lint` (fix: `npm run lint:fix`) | | Format | `npm run format` (check: `npm run format:check`) | -| Single test | `npm test -- test/.test.ts` (or `npx vitest run --config config/vitest.config.ts test/.test.ts`) | +| Single test | `npm test -- test/.test.ts` (or `npx vitest run --config config/vitest.config.ts test/.test.ts`) — ⚠ **never** run bare `npm test`, see Testing section | | Build | `npm run build` (esbuild via `scripts/build.mjs`, NOT tsc — `tsc --noEmit` is type-check only) | | Production | `npm run build && systemctl --user restart codeman-web` | @@ -55,7 +55,7 @@ When user says "COM": CI runs `npm run check:lockfile` on every push/PR, so lockfile drift fails the build even if the `version-packages` script is bypassed. -**Version**: 0.6.4 (must match `package.json`) +**Version**: 0.6.5 (must match `package.json`) ## Project Overview @@ -93,6 +93,7 @@ Codeman is a Claude Code session manager with web interface and autonomous Ralph - **Package ≠ product name** — npm: `aicodeman`, product: **Codeman**. Release renames tags accordingly - **Global regex `lastIndex`** — Shared `g`-flag patterns in loops must reset `lastIndex = 0` first, or use the `execPattern()` helper in `utils/regex-patterns.ts` (resets automatically) - **`envOverrides` flow `CLAUDE_CODE_*` / `OPENCODE_*` env vars** — Set via `POST /api/sessions { envOverrides }`, stored on `Session._envOverrides`, exported by `tmux-manager.buildEnvExports()` at spawn time, persisted in `SessionState.envOverrides`. **Do NOT** write these to `/.claude/settings.local.json` — that's the old path and creates UI/disk drift +- **Zod `.optional()` rejects `null`** — accepts `undefined` only. When the frontend builds a request body with `JSON.stringify`, an explicit `null` field is preserved on the wire and fails validation with `INVALID_INPUT`. Convert `null` → `undefined` before stringifying (e.g. `field: value ?? undefined`), or declare the schema `.nullish()`. Real bugs caused: 0.6.4 (`durationMinutes` for ∞ respawn), and the same shape pattern hit `opusContext1mEnabled` in 0.6.3 **Import conventions**: Utils from `./utils`, types from `./types` (barrel), config from specific `./config/*` files. diff --git a/docs/local-echo-overlay-plan.md b/docs/local-echo-overlay-plan.md index 2f9e9ac1..8abc2c34 100644 --- a/docs/local-echo-overlay-plan.md +++ b/docs/local-echo-overlay-plan.md @@ -1,5 +1,7 @@ # Local Echo Overlay — Implementation Plan +> **Status: SHIPPED.** Implementation lives in `packages/xterm-zerolag-input/src/` (overlay-renderer.ts, prompt-finder.ts, cell-dimensions.ts, zerolag-input-addon.ts) with the embedded copy in `src/web/public/app.js`. This document is retained as historical design context. + ## Context User accesses Codeman remotely from Thailand to Switzerland over Tailscale (~200-300ms RTT). @@ -18,9 +20,9 @@ redraws. A DOM overlay sits in a separate rendering layer (z-index 7) and doesn' with Ink's cursor management or screen redraws at all. When Ink redraws (server output arrives), we simply hide the overlay. -**Why it will look indistinguishable:** We use the DOM renderer (not canvas/WebGL) in our -xterm.js v5.3.0, so both terminal text and overlay text are rendered by the same browser -font engine with identical sub-pixel rendering. +**Why it will look indistinguishable:** We use the DOM renderer (not canvas/WebGL), so both +terminal text and overlay text are rendered by the same browser font engine with identical +sub-pixel rendering. (Originally designed against xterm.js v5.3.0; project now on `@xterm/xterm` ^6.0.0 — the internal `_core._renderService.dimensions` access path still works in v6.) ## Key Technical Details (from research) @@ -36,7 +38,7 @@ const top = cursorY * dims.css.cell.height; // CSS pixels, relative to .xterm- - `cursorY` = `terminal.buffer.active.cursorY` (0 to terminal.rows-1, ALREADY viewport-relative) - No scroll offset math needed -### Cell Dimensions (v5.3.0 — no public API, use internal) +### Cell Dimensions (no public API in v5/v6 — use internal; public in v7+) ```js const dims = terminal._core._renderService.dimensions; dims.css.cell.width // e.g., 8.4px diff --git a/package-lock.json b/package-lock.json index bbb225d9..de0e1ff6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "aicodeman", - "version": "0.6.4", + "version": "0.6.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "aicodeman", - "version": "0.6.4", + "version": "0.6.5", "hasInstallScript": true, "license": "MIT", "workspaces": [ diff --git a/package.json b/package.json index 9dd7f4dd..4b36f7d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aicodeman", - "version": "0.6.4", + "version": "0.6.5", "description": "The missing control plane for AI coding agents - run 20 autonomous agents with real-time monitoring and session persistence", "type": "module", "main": "dist/index.js", diff --git a/src/web/public/terminal-ui.js b/src/web/public/terminal-ui.js index 1f9f74ac..e43a62df 100644 --- a/src/web/public/terminal-ui.js +++ b/src/web/public/terminal-ui.js @@ -156,7 +156,7 @@ Object.assign(CodemanApp.prototype, { Promise.resolve().then(() => { // If xterm cleared the textarea, it processed the input -- skip. const val = xtermTextarea.value; - if (!val || val.trim() === '') return; + if (!val || (val.trim() === '' && data !== ' ')) return; // xterm didn't process it -- forward to terminal as if typed. // Emit via onData path by writing to terminal's input handler. this.terminal._core.coreService.triggerDataEvent(data, true);