# Kaku & WezTerm integration notes

Hard-won facts about Kaku and WezTerm relevant to Paws. Read before touching
the Lua, to avoid re-discovering these.

## WezTerm compatibility

`lua/paws.lua` uses only **standard WezTerm Lua APIs** — every call
(`wezterm.mux`, `wezterm.GLOBAL`, `wezterm.action_callback`, `window:mux_window():spawn_tab`, etc.)
works identically in WezTerm. No code changes are needed.

| Difference | Kaku | WezTerm |
|-----------|------|---------|
| Config path | `~/.config/kaku/kaku.lua` | `~/.config/wezterm/wezterm.lua` |
| Auto-reload on save | ✗ — must press **CMD+Shift+R** | ✓ automatic |
| CMD+SHIFT+G | Taken (lazygit) | Free — but Paws uses CMD+G anyway |

The WezTerm install is identical to Kaku: paste `lua/paws.lua` into your config before `return config`.

## Keybindings
- **No auto-reload.** Kaku does not reload `kaku.lua` on save. Press **CMD+Shift+R**
  after every edit, or changes won't take effect.
- **SHIFT keys use the uppercase letter + `CMD|SHIFT`**, e.g. `key = 'P', mods = 'CMD|SHIFT'`.
  Lowercase `key = 'p'` with `SUPER|SHIFT` does NOT match (macOS sends the shifted char).
- **CMD+SHIFT+G is taken** by Kaku (launch lazygit). Other taken CMD|SHIFT letters:
  A, D, E, R, S, W, Y, plus `[ ] Enter`. Plain `CMD+G` is free.
- `wezterm.action_callback` works; prefer it + `wezterm.mux` over `os.execute('kaku cli …')`
  (shelling out to the mux from inside the mux can block/fail).
- `window:toast_notification(...)` — not confirmed to render in Kaku; don't rely on it
  for user feedback. Prefer visible actions (tab switch, `InputSelector`).

## Mux / panes / tabs (Lua API)
- `wezterm.mux.get_tab(id)` / `get_pane(id)` **raise** if the id is gone — wrap in `pcall`.
- Switch tab: `tab:activate()`. Spawn a tab: `window:mux_window():spawn_tab{ args = {...} }`.
- Spawned panes get a **minimal PATH** (`/usr/bin:/bin:...`). Launch games via a login
  shell so PATH resolves: `args = { os.getenv('SHELL'), '-l', '-c', cmd }`.
- State that must survive across the (manual) config reloads lives in `wezterm.GLOBAL`.
- Zooming a pane (`set_zoomed`) hides *all* sibling panes in the tab — bad when the user
  has other sessions split in the same tab. Use a separate **tab** for the game instead.

## Wrapper input / PTY (the `paws` Rust wrapper hosts games)
- The wrapper does **raw stdin → PTY passthrough** in a thread (no crossterm event
  decoding/filtering). Decoding+filtering dropped `Repeat`/`Release` events, so held
  keys reached games only once → "hold to charge" auto-fired. Raw bytes fix it.
- **Key-release needs the kitty keyboard protocol.** A byte stream alone can't tell a
  quick tap from the start of a hold (first ~250ms is identical). Fix:
  `PushKeyboardEnhancementFlags(REPORT_EVENT_TYPES)` so Kaku sends press/repeat/release;
  jump-high fires the jump on Release (snappy taps, small tap = small hop).
- **Gate kitty to crossterm-aware games only.** Enabling it makes Kaku encode ALL keys
  in kitty form; non-crossterm games (tetris/vitetris, C) can't parse them and break.
  The wrapper enables kitty ONLY when `game_cmd == "jump-high"`.
- Enable kitty AFTER `enable_raw_mode` but BEFORE the stdin-passthrough thread starts
  (the `supports_keyboard_enhancement()` query reply arrives on stdin).

## CLI
- `kaku cli` exists (hidden/experimental) with WezTerm-style subcommands
  (`list`, `split-pane`, `spawn`, `activate-tab`, `zoom-pane`, `kill-pane`, …).
- `kaku cli list --format json` does **not** include `user_vars`, so you can't verify
  OSC user vars that way.

## Agent → terminal signal (history)
- OSC 1337 `SetUserVar` from a Kiro hook → Kaku `user-var-changed` Lua event DOES
  work (verified: `paws_agent_busy`/`paws_agent_done` showed up in the GUI log).
- We originally used it for auto tab-switching, but **dropped auto-switch by design**
  (it was the main complexity/bug source and yanked the user mid-game).
- Now: the hook just writes per-session state to `/tmp/paws-sessions/<id>` (busy|done),
  the wrapper renders a status HUD from it, and the user switches manually with CMD+G.
  No OSC, no `user-var-changed` handler. Simpler and predictable.
